正睿2020三月集训day5

正睿2020三月集训day5

A.买到

套路的状压dp

一个小思维点是dp值可以同时作为时间的状态

B. 口罩

题意:删掉K条边再加上K条边,求不同的树的数量

我们考虑二项式反演(钦定到恰好的转化),考虑钦定有(k)条边和原树不同(先断掉)

然后对于(n-k+1=x)个连通块,其形成的不同的树的个数可以用prufer序列求出,即为(n^{x-2}prod a_i), 考虑通过长度为 (x-2) 的prufer序列,点对应联通块来构造树即可。

(a_i) 是第 (i) 个连通块的点数,其实 (prod a_i) 相当于在每个连通块里选个点的方案数,可以树形dp连通块(n^2)求出(sumprod a_i)。最后反演求出恰好的再加起来就做完了。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
inline char gc(){
    return getchar();
}
inline int read(){
	int x=0,pos=1;char ch=gc();
	for(;!isdigit(ch);ch=gc()) if(ch=='-') pos=0;
	for(;isdigit(ch);ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
	return pos?x:-x; 
} 
#define ll long long
#define FOR(i,a,b) for(register int i=a;i<=b;i++)
#define ROF(i,a,b) for(register int i=a;i>=b;i--)
const int mod = 1e9+7;
const int N = 5021;
int dp[N][N][2],sz[N];
struct node{
	int v,nex;
}edge[N*2];
int head[N],top=0;
int f[N],g[N];
void add(int u,int v){
	edge[++top].v=v;
	edge[top].nex=head[u];
	head[u]=top;
}
int n,k;
int ksm(int a,int b){
	int res=1;
	while(b){
		if(b&1){
			res=1ll*res*a%mod;
		}a=1ll*a*a%mod;b>>=1;
	}
	return res;
}
void init(){
	f[0]=1;
	FOR(i,1,N-1) f[i]=1ll*f[i-1]*i%mod;
	g[N-1]=ksm(f[N-1],mod-2);
	ROF(i,N-2,0) g[i]=1ll*g[i+1]*(i+1)%mod;
}
int tmp[N][2];
void dfs(int now,int pre){
	sz[now]=1;
	dp[now][1][0]=dp[now][1][1]=1;
	for(int i=head[now];i;i=edge[i].nex){
		int v=edge[i].v;
		if(v==pre) continue;
		dfs(v,now);
		FOR(i,1,sz[now]+sz[v]) tmp[i][0]=tmp[i][1]=0;
		FOR(i,1,sz[now]){
			FOR(j,1,sz[v]){
				tmp[i+j][0]=(tmp[i+j][0]+1ll*dp[now][i][0]*dp[v][j][1]%mod)%mod;
				tmp[i+j][1]=(tmp[i+j][1]+1ll*dp[now][i][1]*dp[v][j][1]%mod)%mod;
				tmp[i+j-1][0]=(tmp[i+j-1][0]+1ll*dp[now][i][0]*dp[v][j][0]%mod)%mod;
				tmp[i+j-1][1]=(tmp[i+j-1][1]+1ll*dp[now][i][0]*dp[v][j][1]%mod+1ll*dp[now][i][1]*dp[v][j][0]%mod)%mod;
			}
		}
		sz[now]+=sz[v];
		FOR(i,1,sz[now]) dp[now][i][0]=tmp[i][0],dp[now][i][1]=tmp[i][1];
	}
}
int res[N];
ll C(ll a,ll b){
	if(b>a||a<0||b<0) return 0;
	return 1ll*f[a]*g[b]%mod*g[a-b]%mod;
}
int main(){
	n=read(),k=read();
	k=n-k-1;
	init();
	FOR(i,1,n-1){
		int u=read(),v=read();add(u,v);add(v,u);
	}
	dfs(1,0);
	ll tn=ksm(n,mod-2);
	FOR(i,1,n){
		res[i]=1ll*dp[1][i][1]*tn%mod;
		tn=tn*n%mod;
	}
	int ans=0;
	FOR(i,k,n){
		ll w=0;
		FOR(j,i,n){
			if((j-i)&1) w=(w-1ll*C(j,i)*res[n-j]%mod+mod)%mod;
			else w=(w+1ll*C(j,i)*res[n-j]%mod)%mod;
		}
		ans=(ans+w)%mod;
	}
	printf("%lld
",ans);
	return 0;
}

C.了吗

差分转化+对多项式系数是否为0的分析

这个狗日的出题人超大常数(nlog n)开1e6,我谔谔

这是TLE的代码:

#pragma GCC diagnostic error "-std=c++11"
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,pos=1;char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
	return pos?x:-x;
} 
const int N = 4e6+200;
const int mod = 998244353;
#define ll long long
#define FOR(i,a,b) for(register int i=a;i<=b;++i)
#define ROF(i,a,b) for(register int i=a;i>=b;--i)
int n,k,s;
int fa[N];
struct node{
	int v,nex;
}edge[N*2];
int head[N],top=0,w[N],b[N];
void add(int u,int v){
	edge[++top].v=v;
	edge[top].nex=head[u];
	head[u]=top;
}
void dfs(int now,int cnt){
	cnt+=b[now];if(!b[now]) w[cnt]++;
	for(int i=head[now];i;i=edge[i].nex){
		int v=edge[i].v;
		dfs(v,cnt);
	}
}
int p[N*2],q[N*2],nlen,tmp[N*2],omg[N],inv[N];
int f[N],g[N],r[N];
int Lim,lim,li,tp;
int ksm(int a,int b){
	int res=1;
	while(b){
		if(b&1) res=1ll*a*res%mod;
		a=1ll*a*a%mod;b>>=1;
	}
	return res;
} 
void init(){
	f[0]=1;
	FOR(i,1,1e6) f[i]=1ll*f[i-1]*i%mod;
	g[1000000]=ksm(f[1000000],mod-2);
	ROF(i,1e6-1,0) g[i]=1ll*g[i+1]*(i+1)%mod; 
	omg[0]=inv[0]=1;
	omg[1]=ksm(3,(mod-1)/Lim);inv[1]=ksm(omg[1],mod-2);
	FOR(i,2,Lim){
		omg[i]=1ll*omg[i-1]*omg[1]%mod;
		inv[i]=1ll*inv[i-1]*inv[1]%mod;
	}
}
int C(int a,int b){
	if(b>a||a<0||b<0) return 0;
	return 1ll*f[a]*g[b]%mod*g[a-b]%mod;
}
void getr(){
	r[0]=0;
	FOR(i,1,lim-1){
		r[i]=(r[i>>1]>>1)+((i&1)?(1<<(li-1)):0);
	}
}
void ntt(int *a,int opt){
	FOR(i,0,lim-1) if(i<r[i]) swap(a[i],a[r[i]]);
	for(int l=2;l<=lim;l<<=1){
		int m=l/2;
		for(int *g=a;g!=a+lim;g+=l){
			for(int i=0;i<m;i++){
				ll t;t=opt? 1ll*omg[Lim/l*i]*g[i+m]%mod : 1ll*inv[Lim/l*i]*g[i+m]%mod;
				g[i+m]=(g[i]-t+mod)%mod;
				g[i]=(g[i]+t)%mod;
			}
		}
	}
	if(opt==0){
		int iv=ksm(lim,mod-2);
		FOR(i,0,lim-1) a[i]=1ll*a[i]*iv%mod;
	}
}
int FV[N*2];
int nn;
inline void getinv(const int *a,int *b,int n){
	if(n==1) return b[0]=ksm(a[0],mod-2),void();
	getinv(a,b,(n+1)/2);
	lim=1,li=0;while(lim<n*2) lim*=2,li++;
	FOR(i,(n+1)/2,lim-1) b[i]=0;
	FOR(i,0,n-1) FV[i]=a[i];FOR(i,n,lim-1) FV[i]=0;
	getr();
	ntt(FV,1);ntt(b,1);
	FOR(i,0,lim-1) b[i]=(2ll-1ll*FV[i]*b[i]%mod+mod)%mod*b[i]%mod;
	if(n!=nn) ntt(b,0);
}
int main(){
	n=read(),k=read(),s=read();
	Lim=1;while(Lim<2*s+2) Lim*=2;
	init();
	FOR(i,2,n){
		fa[i]=read();
		add(fa[i],i); 
	}
	FOR(i,1,n) b[i]=read();
	dfs(1,0); 
	int flg=0;
	ROF(i,20,0){
		if(!w[i]) continue;
		if((1<<i)>s) continue;
		tp=0; 
		for(int j=0;j*(1<<i)<=s;j++){
			if((w[i]-j)&1) p[j]=(mod-C(w[i],j))%mod;
			else p[j]=C(w[i],j); tp=j;
		}  
		
		if(!flg){
			nlen=tp;
			FOR(j,0,nlen) q[j]=p[j];
			flg=1;
		}else{
			FOR(j,0,nlen) tmp[j*2+1]=0,tmp[j*2]=q[j];
			FOR(j,0,tp) q[j]=tmp[j];
			lim=1;li=0; while(lim<2*tp+2) (lim<<=1),li++;
			getr();
			ntt(p,1);ntt(q,1);
			FOR(j,0,lim-1) p[j]=1ll*q[j]*p[j]%mod;
			ntt(p,0);
			FOR(j,tp+1,lim-1) q[j]=p[j]=0;
			FOR(j,0,tp) q[j]=p[j],p[j]=0; 
			nlen=tp;
		}
	}
	for(register int j=0;j*(k+1)<=tp;++j){
		p[j*(k+1)]=q[j];
	}
	FOR(j,0,tp) tmp[j]=0;
	nn=tp+1;
	getinv(q,tmp,tp+1);
	//FOR(j,tp+1,lim) p[j]=tmp[j]=0;
	ntt(tmp,0)FOR(j,tp+1,lim) p[j]=0;ntt(p,1);
	FOR(j,0,lim-1) tmp[j]=1ll*tmp[j]*p[j]%mod;
	ntt(tmp,0);
	ll an=0;
	FOR(i,0,s){
		an^=tmp[i];
	}
	printf("%lld
",an);
	return 0;
} 

最后抄了个过的。

原文地址:https://www.cnblogs.com/lcyfrog/p/14252244.html