zoj 3874 Permutation Graph

来源:互联网 发布:php上传视频到七牛云 编辑:程序博客网 时间:2024/06/02 00:55

Permutation Graph ZOJ - 3874

Edward has a permutation {a1, a2, … an}. He finds that if he connects each pair (ai, aj) 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 u, v 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 n, m (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,1, vi,2, … vi,ci which denotes the connected component (1 ≤ ci, vi,1, vi,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}.


【分析】

CDQ分治+NTT

首先脑力YY一下可以发现每一个连通块中的数字一定是连续的!而且每一个连通块在序列中的顺序一定是有序的!所以我们每个连通块的方案数单独考虑,最后π一下就好了。

考虑一个大小n的连通块的序列方案数,记为dp[n]

dp[n]=n!n1i=1dp[i](ni)!

我们可以枚举数字1所在连通块的大小来得到这个方程。

观察到原式是一个卷积的形式,所以可以用CDQ分治+NTT来解决。

Ps:我到今天才知道NTT还要求原根…黑箱NTT…


【代码】

//zoj 3874 Permutation Graph #include<bits/stdc++.h>#define M 100000#define ll long long#define fo(i,j,k) for(int i=j;i<=k;i++)using namespace std;const int mod=786433;const int mxn=400005;int n,m,T,L;int a[mxn],b[mxn],dp[mxn];int fac[mxn],t[mxn],R[mxn];inline int read(){    int x=0;char ch=getchar();    while(ch<'0' || ch>'9') ch=getchar();    while(ch>='0' && ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();    return x;}inline int power(int x,int k){    int res=1;    while(k)    {        if(k&1) res=(ll)res*x%mod;        x=(ll)x*x%mod,k>>=1;    }    return res;}inline void NTT(int *a,int f){    fo(i,0,n-1) if(i<R[i]) swap(a[i],a[R[i]]);    for(int i=1;i<n;i<<=1)    {        int wn=power(10,(mod-1)/(i<<1));        for(int j=0;j<n;j+=(i<<1))        {            int w=1;            for(int k=0;k<i;k++,w=(ll)w*wn%mod)            {                int x=a[j+k],y=(ll)w*a[j+k+i]%mod;                a[j+k]=(x+y)%mod;                a[j+k+i]=(x-y+mod)%mod;            }        }    }    if(f==-1)    {        reverse(a+1,a+n);        int inv=power(n,mod-2);        fo(i,0,n-1) a[i]=(ll)a[i]*inv%mod;    }}inline void CDQ(int l,int r){    if(l==r)    {        dp[l]=(dp[l]+fac[l])%mod;        return;    }    int mid=l+r>>1;    CDQ(l,mid);    n=r-l,m=n+n;    fo(i,0,4*n) a[i]=b[i]=0;    fo(i,l,mid) a[i-l]=dp[i];    fo(i,0,r-l) b[i]=fac[i];    for(n=1,L=0;n<=m;n<<=1) L++;    fo(i,0,n-1) R[i]=(R[i>>1]>>1)|((i&1)<<L-1);    NTT(a,1),NTT(b,1);    fo(i,0,n) a[i]=(ll)a[i]*b[i]%mod;    NTT(a,-1);    fo(i,mid+1,r) dp[i]=(dp[i]-a[i-l]+mod)%mod;    CDQ(mid+1,r);}inline void init(){    fac[0]=1;    fo(i,1,M) fac[i]=(ll)fac[i-1]*i%mod;    CDQ(1,M);}int main(){    init();    T=read();    while(T--)    {        int ans=1;        bool flag=1;        n=read(),m=read();        fo(i,1,m)        {            int x=read();            fo(j,1,x) t[j]=read();            sort(t+1,t+x+1);            fo(j,2,x) if(t[j]!=t[j-1]+1) flag=0;            ans=(ll)ans*dp[x]%mod;        }        printf("%d\n",flag?ans:0);    }    return 0;}
原创粉丝点击