ZOJ 3874 Permutation Graph ——分治 NTT
发现每一块一定是按照一定的顺序的。
然后与标号无关,并且相同大小的对答案的影响相同。
然后列出递推式,上NTT+分治就可以了。
然后就可以与输入同阶处理答案了。
#include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define ll long long #define mp make_pair #define maxn (1<<18) #define md 786433 #define g 10 int dp[maxn],fac[maxn],A[maxn],B[maxn],t,n,m,rev[maxn],C[maxn]; int ksm(int a,int b) { int ret=1; for(;b;b>>=1,a=(ll)a*a%md)if(b&1)ret=(ll)ret*a%md; return ret; } void NTT(int * x,int n,int flag) { F(i,0,n-1) if (rev[i]>i) swap(x[rev[i]],x[i]); for (int m=2;m<=n;m<<=1) { int mid=m>>1,wn=ksm(10,((md-1)/m*flag+md-1)%(md-1)); for (int i=0;i<n;i+=m) { int w=1; for (int j=0;j<mid;++j) { int u=x[i+j],v=(ll)x[i+j+mid]*w%md; x[i+j]=(u+v)%md;x[i+j+mid]=((u-v)%md+md)%md; w=(ll)w*wn%md; } } } if (flag==-1) { int inv=ksm(n,md-2); F(i,0,n-1) x[i]=(ll)x[i]*inv%md; } } void CDQ(int l,int r) { if(l==r)return;int mid=l+r>>1;CDQ(l,mid); int n=mid-l+r-l,m=1;while((1<<m)<n)++m;n=(1<<m); F(i,0,n-1)A[i]=B[i]=0; F(i,l,mid)A[i-l]=dp[i];F(i,1,r-l) B[i-1]=fac[i]; F(i,1,n-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(m-1)); NTT(A,n,1);NTT(B,n,1); F(i,0,n-1)C[i]=(ll)A[i]*B[i]%md;NTT(C,n,-1); F(i,mid+1,r)dp[i]=((dp[i]-C[i-l-1])%md+md)%md; CDQ(mid+1,r); } int main() { fac[0]=1; F(i,1,100000) fac[i]=(ll)fac[i-1]*i%md; dp[0]=0; F(i,1,100000) dp[i]=fac[i]; CDQ(1,100000); scanf("%d",&t); while(t--) { int ans=1,k,x; scanf("%d%d",&n,&m); F(i,1,m) { int mn=n+1,mx=-1; scanf("%d",&k); ans=(ll)ans*dp[k]%md; F(j,1,k) scanf("%d",&x),mn=min(mn,x),mx=max(mx,x); if (k!=mx-mn+1) ans=0; } printf("%d\n",ans); } }