【BZOJ3684】大朋友和多叉树

多项式功底太差。。
对于\(F(G(x))=x\)

\[[x^n]F(x)=\frac{1}{n}[x^{-1}]\frac{1}{G^n(x)} \]

\[[x^n]H(F(x))=\frac{1}{n}[x^{-1}]H'(x)\frac{1}{G^n(x)} \]

或者规范一点的写法是\([x^n]F(x)=\frac{1}{n}[x^{n-1}](\frac{x}{G(x)})^n\)
对于这题 令\([x^i]F(x)\)为包含\(i\)个叶子节点的合法树个数

\[F(x)=x+\sum_{i\in D}F^i(x) \]

枚举有几个儿子,\(+x\)是可以让这个节点成为叶子

\[F(x)-\sum_{i\in D}F^i(x)=x \]

\(G(x)=x-\sum_{i\in D}x^i\)
\(G(F(x))=x\)
代码为了偷懒写一个\(O(n\log^2 n)\)的快速幂。。

#include
using namespace std;
#define fp(i,l,r) for(register int (i)=(l);i<=(r);++(i))
#define fd(i,l,r) for(register int (i)=(l);i>=(r);--(i))
#define fe(i,u) for(register int (i)=front[(u)];(i);(i)=e[(i)].next)
#define mem(a) memset((a),0,sizeof (a))
#define O(x) cerr<<#x<<':'<=10)wr(x/10);
    putchar('0'+x%10);
}
const int MAXN=280000,mod=950009857;
int a[MAXN],b[MAXN],tr[MAXN],lim,c[MAXN],G[MAXN],gg[MAXN],n,m;
inline void tmod(int &x){x%=mod;}
inline void rmod(int &x){x+=x>>31&mod;} 
inline int qpow(int a,int b){
	int res=1;
	for(;b;b>>=1,tmod(a*=a))
	if(b&1)tmod(res*=a);
	return res;
}
inline int ginv(int x){return qpow(x,mod-2);}
inline void ntt(int a[],bool flag){
	fp(i,0,lim-1)if(i>1]>>1)|(i&1?lim>>1:0);
}
void getinv(int deg,int a[],int b[]){
	if(deg==1){b[0]=qpow(a[0],mod-2);return;}
	getinv((deg+1)/2,a,b);
	getlim(deg*2-1);
	fp(i,0,deg-1)c[i]=a[i];fp(i,deg,lim-1)c[i]=0;
	ntt(c,0);ntt(b,0);
	fp(i,0,lim-1)tmod(b[i]=2*b[i]+mod-c[i]*b[i]%mod*b[i]%mod);
	ntt(b,1);
	fp(i,deg,lim-1)b[i]=0; 
}
main(){
	G[0]=1;G[1]=qpow(7,(mod-1)/(1<<18));
	fp(i,2,MAXN-1)tmod(G[i]=G[i-1]*G[1]);
	n=read();m=read();
	a[0]=1;fp(i,1,m)a[read()-1]=mod-1;
	b[0]=1;getlim(n*2);
	for(int k=n;k;k>>=1){
		ntt(a,0);
		if(k&1){
			ntt(b,0);
			fp(i,0,lim-1)tmod(b[i]*=a[i]);
			ntt(b,1);fp(i,n,lim-1)b[i]=0;
		}
		fp(i,0,lim-1)tmod(a[i]*=a[i]);
		ntt(a,1);fp(i,n,lim-1)a[i]=0;
	} 
	mem(a);getinv(n,b,a);
	printf("%lld\n",a[n-1]*ginv(n)%mod);
	puts("");return 0;
}

你可能感兴趣的:(【BZOJ3684】大朋友和多叉树)