zoukankan      html  css  js  c++  java
  • ZOJ 3874 Permutation Graph 分治NTT

    Permutation Graph

    Time Limit: 2 Seconds      Memory Limit: 65536 KB

    Edward has a permutation {a1a2, … an}. He finds that if he connects each pair (aiaj) such that i < j and ai > aj, he will get a graph.

    For example, if the permutation is {2, 3, 1, 4}, then 1 and 2 are connected and 1 and 3 are connected.

    Edward lost his permutation, but he does know the connected components of the corresponding graph. He wants to know how many permutations will result in the same connected components.

    Note that two vertices uv belong to the same connected component if there exists a sequence of vertices starting with u and ending with v such that every two subsequent vertices in the sequence are connected by an edge.

    Input

    There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

    The first line contains two integers nm (1 ≤ m ≤ n ≤ 100000), indicating the length of the permutation and the number of connected components in the graph.

    Each of the following m lines contains an integer ci which denotes the size of i-th connected component, followed by ci distinct integers vi,1vi,2, … vi,ci which denotes the connected component (1 ≤ civi,1vi,2, … vi,ci ≤ n).

    It is guaranteed that every number will appear in exact one connected component and c1 + c2 + … + cm = n.

    Output

    For each case, output the answer modulo 786433.

    Sample Input

    2
    4 4
    1 1
    1 2
    1 3
    1 4
    4 2
    3 1 2 3
    1 4
    

    Sample Output

    1
    3
    

    Hint

    For the second case, the three permutations is: {2, 3, 1, 4}, {3, 2, 1, 4}, {3, 1, 2, 4}.

    题解:

      一个联通块的点必须是连续的

      构造一个dp方程,令dp[i] 表示 i 个连续的点,能形成联通块的 方案数

      那么 : dp[i] = n! - i*dp[n - i]    这里 i 取遍1~n-1

      发现 i * dp[n-i], 就是卷积,取的模又是 费马素数, 那就NTT求解了

      还要用cdq分治优化下

    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define ls i<<1
    #define rs ls | 1
    #define mid ((ll+rr)>>1)
    #define pii pair<int,int>
    #define MP make_pair
    typedef long long LL;
    const long long INF = 1e18+1LL;
    const double pi = acos(-1.0);
    const int N = 1e6+10, M = 1e3+20,inf = 2e9,mod = 786433;
    
    const LL G = 10, P = 786433;
    
    LL mul(LL x,LL y){
        return (x*y-(LL)(x/(long double)P*y+1e-3)*P+P)%P;
    }
    LL qpow(LL x,LL k,LL p){
        LL ret=1;
        while(k){
            if(k&1) ret=mul(ret,x);
            k>>=1;
            x=mul(x,x);
        }
        return ret;
    }
    LL wn[50];
    void getwn(){
        for(int i=1; i<=25; ++i){
            int t=1<<i;
            wn[i]=qpow(G,(P-1)/t,P);
        }
    }int len;
    void NTT_init() {
        getwn();
    }
    
    void NTT(LL y[],int op){
        for(int i=1,j=len>>1,k; i<len-1; ++i){
            if(i<j) swap(y[i],y[j]);
            k=len>>1;
            while(j>=k){
                j-=k;
                k>>=1;
            }
            if(j<k) j+=k;
        }
        int id=0;
        for(int h=2; h<=len; h<<=1) {
            ++id;
            for(int i=0; i<len; i+=h){
                LL w=1;
                for(int j=i; j<i+(h>>1); ++j){
                    LL u=y[j],t=mul(y[j+h/2],w);
                    y[j]=u+t;
                    if(y[j]>=P) y[j]-=P;
                    y[j+h/2]=u-t+P;
                    if(y[j+h/2]>=P) y[j+h/2]-=P;
                    w=mul(w,wn[id]);
                }
            }
        }
        if(op==-1){
            for(int i=1; i<len/2; ++i) swap(y[i],y[len-i]);
            LL inv=qpow(len,P-2,P);
            for(int i=0; i<len; ++i) y[i]=mul(y[i],inv);
        }
    }
    
    int T,n,m;
    LL y[N],yy[N],dp[N],f[N];
    void cdq(int ll,int rr) {
        if(ll == rr) return ;
        cdq(ll,mid);
        len = 1;
        while(len <= rr-ll+1) len<<=1;
        for(int i = 0; i < mid-ll+1; ++i) y[i] = dp[ll+i];
        for(int i = mid-ll+1; i < len; ++i) y[i] = 0;
        for(int i = 0; i < len; ++i) yy[i] = f[i+1];
        NTT(y,1),NTT(yy,1);
        for(int i = 0; i < len; ++i) y[i] = (y[i] * yy[i])%P;
        NTT(y,-1);
        for(int i = mid; i < rr; ++i)
            dp[i+1]  = ((dp[i+1] - y[i - ll])%mod + mod) % mod;
        cdq(mid+1,rr);
    }
    int main() {
        NTT_init();
        f[0] = 1;
        for(int i = 1; i <= 100005; ++i) {
            f[i] = 1LL* f[i-1] * i % mod;
            dp[i] = f[i];
        }
        cdq(1,100001);
        scanf("%d",&T);
        while(T--) {
            scanf("%d%d",&n,&m);
            int ans = 1;
            for(int i = 1; i <= m; ++i) {
                int x,y,mi = inf,mx = 0;
                scanf("%d",&x);
                ans = (ans * dp[x]) % mod;
                for(int j = 1; j <= x; ++j) {
                    scanf("%d",&y);
                    mx = max(mx,y);
                    mi = min(mi,y);
                }
                if(mx - mi + 1 != x) ans = 0;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    .NET 4.0 System.Threading.Tasks学习笔记
    c#初学-多线程中lock用法的经典实例
    Spring3 Schedule Task之注解实现 (两次起动Schedule Task 的解决方案)
    支持向量机中的函数距离的理解
    Sqlserver 2016 R Service环境安装的各种错误(坑)解决办法
    Sql server的Merge语句,源表中如果有重复数据会导致执行报错
    对IIS7经典模式和集成模式的理解(转载)
    VisualStudio编译项目时,提示bin目录和obj目录下的文件不能写的错误处理的解决办法
    SQL Server 全文索引介绍(转载)
    sql server全文索引使用中的小坑 (转载)
  • 原文地址:https://www.cnblogs.com/zxhl/p/7220709.html
Copyright © 2011-2022 走看看