[集训队作业2013]城市规划
题链
式子部分非常的巧妙。
假设 \(g\),\([x^t]g(x)\) 表示 \(t\) 个点的简单有标号无向图的方案数。
再假设一个 \(f\),在前面那个基础上加上 联通 的前提。
由于一个图可以看做是若干个联通块,那么我们可以钦定最后加入的那个点所在的联通块,得到式子:
\[[x^t]g(x)=\sum_{i=1}^t \begin{pmatrix} {t-1}\\{i-1} \end{pmatrix} [x^i]f(x)\times [x^{t-i}]g(x)
\]
把组合数展开,三项分别放到 合适 的位置,就得到了 \(\texttt{EGF}\) 的形式。
\[\frac{[x^t]g(x)}{(t-1)!}=\sum_{i=1}^t \frac{[x^i]f(x)}{(i-1)!} \times \frac{[x^{t-i}]g(x)}{(t-i)!}
\]
那么便可以对后面进行求逆,然后直接乘起来就好了。
#include <stdio.h>
#include <string.h>
#define LL long long
using namespace std;
const int N=3e5+3;
const int M=1004535809;
const int K=3;
inline int rin()
{
int s=0;
bool bj=false;
char c=getchar();
for(;(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')bj=true,c=getchar();
for(;c>='0'&&c<='9';c=getchar())s=(s<<1)+(s<<3)+(c^'0');
if(bj)s=-s;
return s;
}
inline void jh(int &x,int &y){if(x!=y)x^=y^=x^=y;return;}
inline int prpr(int x,int y){return 1LL*x*y%M;}
inline int ksm(int x,LL y){int ans=1;for(;y;y>>=1){if(y&1)ans=prpr(ans,x);x=prpr(x,x);}return ans;}
const int Kr=ksm(K,M-2);
int lens;
int num[N];
inline void init(int L)
{
int lg=0;
for(lens=1;lens<L;lens<<=1)lg++;
for(int i=1;i<lens;i++)num[i]=((num[i>>1]>>1)|((i&1)<<lg-1));
return;
}
inline void NTT(int *a,int tag)
{
for(int i=0;i<lens;i++)if(num[i]>i)jh(a[i],a[num[i]]);
for(int i=1;i<lens;i<<=1)
{
int Gyq=ksm((tag==1?K:Kr),(M-1)/(i<<1));
for(int j=0;j<lens;j+=(i<<1))
{
int Zjj=1;
for(int k=0;k<i;k++,Zjj=prpr(Zjj,Gyq))
{
int x=a[j+k],y=prpr(a[j+k+i],Zjj);
a[j+k]=(x+y)%M;
a[j+k+i]=(x-y+M)%M;
}
}
}
if(!tag)
{
int Gyq=ksm(lens,M-2);
for(int i=0;i<lens;i++)a[i]=prpr(a[i],Gyq);
}
return;
}
int Alpha[N];
inline void inv(int *a,int *b,int L)
{
if(L==1){b[0]=ksm(a[0],M-2);return;}
inv(a,b,(L+1)>>1);
init((L<<1)-1);
for(int i=0;i<lens;i++)Alpha[i]=(i<L)?(a[i]):(0);
NTT(Alpha,1);
NTT(b,1);
for(int i=0;i<lens;i++)b[i]=prpr(b[i],(2-prpr(b[i],Alpha[i])));
NTT(b,0);
for(int i=L;i<lens;i++)b[i]=0;
return;
}
inline void inv_(int *a,int *b,int L){memset(b,0,sizeof(b));inv(a,b,L);return;}
int n;
int sl[N];
int sr[N];
inline void Inv(int n)
{
sl[0]=sr[0]=1;
for(int i=1;i<=n;i++)sl[i]=prpr(sl[i-1],i);
sr[n]=ksm(sl[n],M-2);
for(int i=n-1;i>=1;i--)sr[i]=prpr(sr[i+1],i+1);
return;
}
int Beta[N];
int Zeta[N];
int Zeta_[N];
int main()
{
int i,j;
n=rin();
Inv(n);
for(int i=0;i<=n;i++)
{
Beta[i]=ksm(2,(1LL*i*(i-1)>>1));
Zeta[i]=prpr(Beta[i],sr[i]);
Beta[i]=prpr(Beta[i],sr[i-1]);
}
inv_(Zeta,Zeta_,n+1);
LL ans=0;
for(int i=0;i<=n;i++)ans+=prpr(Beta[i],Zeta_[n-i]);
ans=(ans%M+M)%M;
ans=prpr(ans,sl[n-1]);
printf("%d\n",ans);
return 0;
}
$$\texttt{Dirty Deeds Done Dirt Cheap}$$