[多项式求逆]JZOJ 3303 城市规划

Description

刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.

刚才说过, 阿狸的国家有n 个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通.

为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.

好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n 个点的简单(无重边无自环)无向连通图数目.

由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^21 + 1)即可.
 

Input

仅一行一个整数n(<=130000)

Output

仅一行一个整数, 为方案数mod 1004535809.
 

Sample Input

输入1:
3
输入2:
4
输入3:
100000

Sample Output

输出1:
4
输出2:
38
输出3:
829847355
 

Data Constraint

对于20%的数据, n <= 10

对于40%的数据, n <= 1000

对于60%的数据, n <= 30000

对于80%的数据, n <= 60000

对于100%的数据, n <= 130000

 

分析

很裸的求无向连通图个数,求逆瞎搞

 
#include <iostream>
#include <cstdio>
#include <cmath>
#include <memory.h>
using namespace std;
const int N=524288;
const int P=1004535809;
int n,rev[N],j;
int fake_a[N],fake_b[N],a[N],b[2][N],C[N],inv[N];

void Get_Rev(int bit,int mxb) {for (int i=1;i<mxb;i++)    rev[i]=(rev[i>>1]>>1)|((i&1)<<bit-1);}

int Pow(int x,int y) {int ans=1;for (;y;y>>=1,x=1ll*x*x%P) ans=1ll*ans*(y&1?x:1)%P;return ans;}

void NTT(int *a,int n,int idft) {
    for (int i=1;i<=n;i++) if (rev[i]>i) swap(a[rev[i]],a[i]);
    for (int mlen=1;mlen<n;mlen<<=1) {
        int g1=Pow(3,(P-1)/(mlen<<1));
        if (idft<0) g1=Pow(g1,P-2);
        for (int l=0,len=mlen<<1;l<n;l+=len) {
            int gk=1;
            for (int i=l;i<l+mlen;i++) {
                int x=a[i],y=1ll*a[i+mlen]*gk%P;
                a[i]=(x+y)%P;a[i+mlen]=(x-y+P)%P;
                gk=1ll*gk*g1%P;
            }
        }
    }
    if (idft<0) {
        int inv=Pow(n,P-2);
        for (int i=0;i<n;i++) a[i]=1ll*a[i]*inv%P;
    }
}

void Roll_Multi(int *a,int *b,int mxb) {
    for (int i=0;i<mxb;i++) fake_a[i]=0;
    for (int i=0;i<mxb;i++) fake_b[i]=0;
    int half=mxb>>1;
    for (int i=0;i<half;i++) fake_a[i]=a[i],fake_b[i]=b[i];
    NTT(fake_a,mxb,1);NTT(fake_b,mxb,1);
    for (int i=0;i<mxb;i++) fake_a[i]=1ll*fake_a[i]*fake_b[i]%P;
    NTT(fake_a,mxb,-1);
    for (int i=0;i<mxb;i++) a[i]=fake_a[i];
}

void Calc_Inv() {
    int bit=1;
    b[j][0]=Pow(a[0],P-2);
    for (int mlen=1,len=2;mlen<(n<<1);mlen<<=1,len<<=1,j^=1,++bit) {
        memset(b[j^1],0,sizeof b[j^1]);Get_Rev(bit,len);
        for (int i=0;i<mlen;i++) b[j^1][i]=2ll*b[j][i]%P;
        Roll_Multi(b[j],b[j],len);
        Roll_Multi(b[j],a,len);
        for (int i=0;i<mlen;i++) b[j^1][i]=(b[j^1][i]-b[j][i]+P)%P;
    }
}

int main() {
    scanf("%d",&n);
    inv[0]=1;
    for (int i=1;i<=n;i++) C[i]=Pow(2,1ll*i*(i-1)/2%(P-1)),inv[i]=1ll*inv[i-1]*Pow(i,P-2)%P;
    C[0]=C[1]=1;
    n++;
    for (int i=0;i<n;i++) a[i]=1ll*C[i]*inv[i]%P;
    Calc_Inv();
    memset(a,0,sizeof a);
    for (int i=1;i<n;i++) a[i]=1ll*C[i]*inv[i-1]%P;
    int mxb=1;
    while (mxb<(n<<1)) mxb<<=1;
    for (int i=n-1;i<mxb;i++) b[j][i]=0;
    Roll_Multi(b[j],a,mxb);
    printf("%lld",1ll*b[j][n-1]*Pow(inv[n-2],P-2)%P);
}
View Code

 

 

posted @ 2019-07-08 07:45  Vagari  阅读(204)  评论(0编辑  收藏  举报