题解:
显然一个整体一定是连续的一段数。
所以我们预处理长度为$len$的一组数的组成方案数就好了。
于是$dp$。
$dp[0]=0$,$dp[i]=i!-\sum(k!*dp[i-k])$
$i!$,这$i$个数瞎放。
$k!*dp[i-k]$,第$i$个数放到倒数第$k+1$位上,此时前面构成一个长度为$i-k$的联通块(方案数已经推出来了),
后面$k$个数瞎放。
怎么求?
不会。
学长说,$FFT$和$CDQ$更配哦。
然后$CDQ$里面用$FFT$搞卷积。
处理之后直接出解。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 305000; const int MOD = 786433; typedef long long ll; template<typename T> inline void read(T&x) { T f=1,c=0;char ch = getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } ll fastpow(ll x,int y) { ll ret = 1; while(y) { if(y&1)ret=ret*x%MOD; x=x*x%MOD; y>>=1; } return ret; } int to[4*N],lim=1,L; ll inv,W[4*N]; void ntt(ll *a,int len,int k) { for(int i=0;i<len;i++) if(i<to[i])swap(a[i],a[to[i]]); for(int i=1;i<len;i<<=1) { ll w0 = W[i]; for(int j=0;j<len;j+=(i<<1)) { ll w = 1; for(int o=0;o<i;o++,w=w*w0%MOD) { ll w1 = a[j+o],w2 = a[j+o+i]*w%MOD; a[j+o] = (w1+w2)%MOD; a[j+o+i] = (w1-w2+MOD)%MOD; } } } if(k==-1) { for(int i=1;i<(len>>1);i++)swap(a[i],a[len-i]); for(int i=0;i<len;i++)a[i]=a[i]*inv%MOD; } } int T,n,m; ll f[N],jc[N]; ll a[4*N],b[4*N],c[4*N]; void cdq(int l,int r) { if(l==r)return ; int mid = (l+r)>>1; cdq(l,mid); lim=1,L=0; while(lim<=(r-l+1))lim<<=1,L++; inv = fastpow(lim,MOD-2); for(int i=1;i<lim;i<<=1)W[i]=fastpow(10,(MOD-1)/(i<<1)); for(int i=0;i<lim;i++)a[i]=b[i]=0; for(int i=1;i<=r-l+1;i++)a[i]=jc[i]; for(int i=1;i<=mid-l+1;i++)b[i]=f[i+l-1]; for(int i=1;i<lim;i++)to[i]=((to[i>>1]>>1)|((i&1)<<(L-1))); ntt(a,lim,1),ntt(b,lim,1); for(int i=0;i<lim;i++)c[i]=a[i]*b[i]%MOD; ntt(c,lim,-1); for(int i=mid+1;i<=r;i++)f[i]=(f[i]-c[i-l+1]+MOD)%MOD; cdq(mid+1,r); } int main() { read(T); f[0]=jc[0]=1; for(int i=1;i<=100000;i++)f[i]=jc[i]=jc[i-1]*i%MOD; cdq(1,100000); while(T--) { read(n),read(m); ll ans = 1; for(int x,mx,mn,i=1;i<=m;i++) { read(x);mx=-1,mn=N; for(int j=1,y;j<=x;j++)read(y),mx=max(mx,y),mn=min(mn,y); if(mx-mn+1!=x)ans=0; ans=ans*f[x]%MOD; } printf("%lld\n",ans); } return 0; }