1. 程式人生 > >ZOJ 3874 Permutation Graph 分治NTT

ZOJ 3874 Permutation Graph 分治NTT

printf air u+ var for each 還要 turn tee bit

Permutation Graph

Time Limit: 2 Seconds Memory Limit: 65536 KB

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 ≤ mn

≤ 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,cin).

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\n",ans);
    }
    return 0;
}

ZOJ 3874 Permutation Graph 分治NTT