题解:P16365 [OOI 2026] Tasks from Sasha
拜谢大龙 @wzc6666 给我讲这题。
首先稍加思考可以得到一个
如果
如果
如果染上,那么他的所有儿子都可以给
如果
暴力转移式子为:
然后我们注意到
为了方便书写,我们设
白色中间非叶子节点,每个点都有
红色中间非叶子节点没区别。
接下来考虑叶子,白叶子按照上边的转移为
此时我们发现啥也没优化,时间复杂度甚至多个快速幂的
此时我们发现,所有白叶子本质上只有大小的区别,所以我们记
现在底下紧挨着白叶子的红色中间节点的只选一个子树的我们想快速算,
现在考虑一个大小为
其他儿子我们正常钦定即可,即
最后的转移为
然后发现这个不同叶子大小种类是等差数列量级
设第
因为非叶子有
再枚举
最终时间复杂度
Code.
#include<bits/stdc++.h>
const int mod=998244353;
using namespace std;
#define int long long
#define main(x) MiAn();int mIaN();main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;if(strlen(#x))cin>>t;while(t--)mIaN();cerr<<"Time: "<<1.0*clock()/CLOCKS_PER_SEC<<"s\n";}int mIaN()
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define mem(a,b) memset((a),(b),sizeof(a))
#define all(x) (x).begin(),(x).end()
#define abs_(x) ((x)<0?-(x):(x))
#define sz(x) ((int)(x).size())
#define ull unsigned long long
#define pb push_back
#define fi first
#define se second
const int block=911;
int pw1[2005][block];
int pw2[2005][1100];
int ipw1[2005][block];
int ipw2[2005][1100];
int qpow(int a,int b){
int res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int fastpow(int a,int b){return pw1[a][b%block]*pw2[a][b/block]%mod;}
int fastinv(int a,int b){return ipw1[a][b%block]*ipw2[a][b/block]%mod;}
int n,k;
int tot;
int B[1000005];
int fa[1000005];
int sc[1000005];
int sz[1000005];
int sum[1000005];
bool col[1000005];
bool inp[1000005];
int f[4005][2005];
int dp[4005][2005];
int id[1000005];
int cnt[1000005];
vector<int>mp[1000005];
int faid_to_sc[1000005];
vector<int>newedge[1000005];
void initpow(int n){
rep(a,1,k+2){
int ia=qpow(a,mod-2);
pw1[a][0]=pw2[a][0]=1;
ipw1[a][0]=ipw2[a][0]=1;
rep(j,1,block-1){
pw1[a][j]=pw1[a][j-1]*a%mod;
ipw1[a][j]=ipw1[a][j-1]*ia%mod;
}
int x=pw1[a][block-1]*a%mod;
int y=ipw1[a][block-1]*ia%mod;
rep(j,1,n/block){
pw2[a][j]=pw2[a][j-1]*x%mod;
ipw2[a][j]=ipw2[a][j-1]*y%mod;
}
}
}
void dfs(int u,int faa){
sum[u]=sum[faa]+col[u];
id[u]=++tot;
for(int v:mp[u]){
if(v==faa) continue;
if(!col[v]&&!(sz(mp[v])^1)) continue;
dfs(v,u);
}
vector<int>types;
int qwq=0;
for(int v:mp[u]){
if(v==faa) continue;
if(!col[v]&&!(sz(mp[v])^1)){
if(!cnt[sz[v]]) types.pb(sz[v]);
cnt[sz[v]]++;
qwq+=sz[v];
}
}
rep(i,0,sum[u]){
dp[id[u]][i]=fastpow(i+1,qwq);
for(int v:mp[u]){
if(v==faa) continue;
if(!col[v]&&!(sz(mp[v])^1)) continue;
dp[id[u]][i]=dp[id[u]][i]*f[id[v]][i]%mod;
}
}
rep(i,0,sum[u]-col[u]){
if(!col[u]) f[id[u]][i]=dp[id[u]][i]*fastpow(i+1,sz[u])%mod;
else{
int ans=((i+2)*dp[id[u]][i+1]-(i+1)*dp[id[u]][i]%mod+mod)%mod;
int zero=0,dyy=1,res=0,awa=0;
for(int v:mp[u]){
if(v==faa) continue;
if(!col[v]&&!(sz(mp[v])^1)) continue;
int a=f[id[v]][i];
int b=f[id[v]][i+1];
if(!a) zero++,awa=b;
else dyy=dyy*a%mod,res=(res+(b-a+mod)*qpow(a,mod-2))%mod;
}
for(int s:types) res=(res+cnt[s]*(fastpow(i+2,s)*fastinv(i+1,s)%mod-1+mod))%mod;
if(!zero) res=res*dp[id[u]][i]%mod;
else if(!(zero^1)) res=awa*dyy%mod*fastpow(i+1,qwq)%mod;
else res=0;
f[id[u]][i]=(ans-(i+1)*res%mod+mod)%mod;
}
}
for(int s:types) cnt[s]=0;
}
int main(){
cin>>n>>k;
initpow(n);
rep(i,1,k){int x;cin>>x;inp[x]=1;}
rep(i,2,n){cin>>fa[i];mp[i].pb(fa[i]);mp[fa[i]].pb(i);}
rep(i,1,n) sc[i]=((i^1)&&!(inp[i]|inp[fa[i]])?sc[fa[i]]:++fa[0]),sz[sc[i]]+=!inp[i];
rep(i,1,n) if(inp[i]) col[sc[i]]=1;
rep(u,1,n){for(int v:mp[u]){if(sc[u]^sc[v]) newedge[sc[u]].pb(sc[v]);}}
n=fa[0];
rep(u,1,n){sort(all(newedge[u]));newedge[u].erase(unique(all(newedge[u])),newedge[u].end());mp[u].clear();for(int v:newedge[u]){mp[u].pb(v);}}
dfs(1,0);
cout<<f[1][0];
return 0;
}