zoukankan      html  css  js  c++  java
  • [多项式求逆]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
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    Linux进程间通信之信号量
    C语言文件操作
    Linux多线程同步方法
    Linux进程间通信之共享内存
    关于P2P下载的思考
    学习Jxta,初窥门径
    庆祝一下,基于JXTA的P2P文件共享传输文件测试成功。
    关于java nio在windows下实现
    Java aio和JSR 203
    关于文件目录的P2P共享问题
  • 原文地址:https://www.cnblogs.com/mastervan/p/11149093.html
Copyright © 2011-2022 走看看