zoukankan      html  css  js  c++  java
  • 「雅礼集训 2018 Day4」Magic(分治NTT)

    「雅礼集训 2018 Day4」Magic(分治NTT)

    题目的条件简直无法计算恰好为(k)的方案数,所以考虑计算(ge k)的方案数

    所以可以强制有(k)个相邻位置相同,但是不确定相同的是那些颜色

    对每个颜色(a_i)考虑,设把(a_i)这个颜色分成了(b_i)个联通块(即强制了(a_i-b_i)个相邻位置相同)

    那方案数就是(C(a_i-1,b_i-1))(是一个简单的插板问题)

    得到每种颜色的联通块个数(b_i),那么这些联通块之间排列的方案数就是(frac{(sum b_i)!}{b_i!})

    容易得到(a_i ightarrow b_i)的方案数,直接合并(b_i)的方案数,是一个背包问题,所以考虑用分治(NTT)快速合并

    那么得到了(sum b_i=n-k)的所有方案,复杂度(O(nlog nlog m))

    最后的容斥比较明显的是一个二项式反演的形式,可以(O(n))计算

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    #define pb push_back
    #define Mod1(x) ((x>=P)&&(x-=P))
    #define Mod2(x) ((x<0)&&(x+=P))
    
    char IO;
    int rd(){
    	int s=0;
    	while(!isdigit(IO=getchar()));
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return s;
    }
    
    const int N=1<<17,P=998244353;
    
    int n,m,k;
    int Inv[N+1],Fac[N+1],FInv[N+1];
    ll C(int n,int m){ return n<0||m<0||n<m? 0 : 1ll*Fac[n]*FInv[m]%P*FInv[n-m]%P; }
    ll qpow(ll x,ll k=P-2){
    	ll res=1;
    	for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
    	return res;
    }
    typedef vector <int> Poly;
    int w[N|10],rev[N];
    void Init(){
    	Inv[0]=Inv[1]=Fac[0]=Fac[1]=FInv[0]=FInv[1]=1;
    	rep(i,2,N){
    		Fac[i]=1ll*Fac[i-1]*i%P;
    		Inv[i]=1ll*(P-P/i)*Inv[P%i]%P;
    		FInv[i]=1ll*FInv[i-1]*Inv[i]%P;
    	}
    	w[N>>1]=1;
    	ll t=qpow(3,(P-1)/N);
    	rep(i,(N>>1)+1,N-1) w[i]=w[i-1]*t%P;
    	drep(i,(N>>1)-1,1) w[i]=w[i<<1];
    }
    
    int Init(int n){
    	int R=1,cc=-1;
    	while(R<n) R<<=1,cc++;
    	rep(i,1,R-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<cc);
    	return R;
    }
    void NTT(int n,Poly &a,int f){
    	if((int)a.size()<n) a.resize(n);
    	rep(i,1,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
    	for(int i=1;i<n;i<<=1){
    		int *e=w+i;
    		for(int l=0;l<n;l+=i*2){
    			for(int j=l;j<l+i;++j) {
    				int t=1ll*a[j+i]*e[j-l]%P;
    				a[j+i]=a[j]-t; Mod2(a[j+i]);
    				a[j]+=t; Mod1(a[j]);
    			}
    		}
    	}
    	if(f==-1){
    		reverse(a.begin()+1,a.end());
    		rep(i,0,n-1) a[i]=1ll*a[i]*Inv[n]%P;
    	}
    }
    
    Poly operator * (Poly a,Poly b){
    	int n=a.size()+b.size()-1,R=Init(n);
    	NTT(R,a,1),NTT(R,b,1);
    	rep(i,0,R-1) a[i]=1ll*a[i]*b[i]%P;
    	NTT(R,a,-1),a.resize(n);
    	return a;
    }
    
    Poly Solve(int l,int r){
    	if(l==r){
    		int x=rd();
    		Poly F(x+1);
    		rep(y,1,x) F[y]=C(x-1,y-1)*FInv[y]%P;
    		return F;
    	}
    	int mid=(l+r)>>1;
    	return Solve(l,mid)*Solve(mid+1,r);
    }
    
    int main(){
    	freopen("magic.in","r",stdin),freopen("magic.out","w",stdout);
    	Init(),n=rd(),m=rd(),k=rd();
    	Poly dp=Solve(1,n);
    	rep(i,n,m) dp[i]=1ll*dp[i]*Fac[i]%P;
    	int i=m-k;
    	rep(j,n,i-1) dp[i]=(dp[i]+(((i-j)&1)?-1:1)*dp[j]*C(m-j,m-i)%P+P)%P;
    	ll ans=(dp[i]%P+P)%P;
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    格式化数字保留N位小数
    listbox美化
    501 Not Implemented:服务器不支持实现请求所需要的功能。例如,客户发出了一个服务器不支持的PUT请求。
    截透明
    CASE WHEN
    c# HttpWebRequest与HttpWebResponse 绝技
    提取网页中的超链接(C#)
    转sqlhelp
    IIS创建虚拟目录
    一次重构的过程
  • 原文地址:https://www.cnblogs.com/chasedeath/p/13159309.html
Copyright © 2011-2022 走看看