终于卡过去了……
这题和求无标号有根树个数的思路差不多,可以先看这里,因为下面一些公式演算会省略中间过程。
设大小为 的好图数目为,其中连通的数目为
注意但时,不连通的好图和连通的好图一一对应,即
考虑生成函数,为何方便,我们设。
一个好图是由若干个连通好图拼成,即
两边取再求导得
再拆回每一项看:
注意,所以,所以
注意时要移项,且,所以得:
设就可以递推了,卡常可过。
也可以分治FFT做到
#include<bits/stdc++.h> #define ll unsigned long long using namespace std; int getint() { int i=0,f=1;char c; for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar()); if(c=='-')c=getchar(),f=-1; for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0'; return i*f; } const int N=100005; int T,n=23333,mod; inline void add(ll &x,int y){x=x+y>=mod?x+y-mod:x+y;} ll f[N],g[N],s[N]; ll Pow(ll x,int y) { ll res=1; for(;y;y>>=1,x=x*x%mod) if(y&1)res=res*x%mod; return res; } int main() { //freopen("lx.in","r",stdin); T=getint(),mod=getint(); f[0]=f[1]=1;for(int i=1;i<=n;i++)s[i]=1; for(int i=1;i<n;i++) { __int128 tmp=0; for(int j=0;j<=i;j++)tmp+=f[j]*s[i+1-j];tmp%=mod; g[i+1]=tmp*Pow(i+1,mod-2)%mod,f[i+1]=g[i+1]*2%mod; for(int j=i+1;j<=n;j+=i+1)add(s[j],tmp); } while(T--)cout<<f[getint()]<<'\n'; return 0; }