版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/85260225
【题目】
原题地址
定义
的补图与
有完全相同的节点,任意两点之间有边当且仅当他们在
中不相邻
定义一个无向简单图是好的满足:一个单点是好的,若干个好的图分别作为连通块所形成的图是好的,一个好的图的补图是好的。
给定一个整数
,求
个节点的本质不同的好图数量,
。
【解题思路】
以下多数参考这里,有部分补充修改。
这个题和无标号生成树计数类似
设
个点的好图数目为
,其中连通图的数目为
,那么显然当
,连通好图与不连通好图是一一对应的,也就是
考虑
的生成函数
,为了方便,设
首先一个好图由若干个连通好图组成,于是我们考虑枚举每个连通好图的贡献,那么一种大小为
的连通好图的贡献是
,因此我们有:
然后对两边同时取
:
再求导:
然后拆回去每一项:
这里注意到
,则
,因此
注意
时要移项,且
,所以得:
设
可以
递推,然后卡常是可以过的。
观察到上面还是一个卷积的形式,于是用分治
可以做到
所以我们就直接上暴力了。
【参考暴力】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=23333;
ll T,mod;
ll f[N+5],g[N+5],s[N+5];
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
ll qpow(ll x,ll y){ll res=1;for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;return res;}
ll upm(ll x){return x>=mod?x-mod:x;}
int main()
{
#ifndef ONLINE_JUDGE
freopen("LOJ6389.in","r",stdin);
freopen("LOJ6389.out","w",stdout);
#endif
T=read();mod=read();
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*qpow(i+1,mod-2)%mod;f[i+1]=g[i+1]*2%mod;
for(int j=i+1;j<=N;j+=i+1)s[j]=upm(s[j]+tmp);
}
cerr<<clock()<<endl;
while(T--) printf("%lld\n",f[read()]);
return 0;
}