LOJ#6389. 「THUPC2018」好图计数 / Count【生成函数】

匿名 (未验证) 提交于 2019-12-03 00:19:01

传送门

终于卡过去了……
这题和求无标号有根树个数的思路差不多,可以先看这里,因为下面一些公式演算会省略中间过程。

设大小为 n 的好图数目为fn,其中连通的数目为gn
注意但n2时,不连通的好图和连通的好图一一对应,即gn=fn/2

考虑生成函数F(x)=fixi,为何方便,我们设f0=1
一个好图是由若干个连通好图拼成,即

F(x)=k>0(i0xik)gk=k>0(1xk)gk

两边取In再求导得
F(x)F(x)=k>0kgkxk11xk

F(x)=F(x)k>0kgkxk11xk

再拆回每一项看:
[xn]F(x)=(n+1)fn+1=i=0nfi([xni]k>0kgkxk11xk)

注意xk11xk=xk1+x2k1+x3k1+...,所以[xn]xk11xk=[k|n+1],所以

(n+1)fn+1=i=0nfik|n+1ikgk

注意i=0时要移项,且f0=1,gi=fi/2,所以得:
n+12fn+1=k|n+1,k<n+1kgk+i=1nfik|n+1ikgk

si=k|ikgk就可以O(n2)递推了,卡常可过。
也可以分治FFT做到O(nlog2n)

#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; }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!