[集训队作业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;
}
posted @ 2020-12-24 16:57  zjjws  阅读(83)  评论(0编辑  收藏  举报