• CF896D Nephren Runs a Cinema


    CF896D Nephren Runs a Cinema

    题意

    售票员最开始没有纸币,每次来一个顾客可以给她一张、拿走她一张或不操作。求出不出现中途没钱给的情况 (n) 名顾客后剩余钱数在 (lsim r) 的方案数。

    思路

    这是我们一道模拟赛题。

    解法 1:套路组合计数。先不考虑不操作的顾客,那么就相当于是求二维平面不过一条直线到达一点的方案数。直接枚举操作顾客数,用组合数减去另外一个组合数然后乘上所有顾客中选这些顾客的方案数即可。

    解法 2:暴力动态规划。每次从至多三个方向转移。

    赛时我先想到第一个解法但是没想到枚举操作人数,以为不可做,于是想到了优化暴力的解法。

    解法 3:解法 2 的优化。求出 (F=(x^{-1}+1+x)^n) ,然后 (f(x)-f(x+2)) 的第 (l sim r) 项的和即为答案。

    ((x^{-1}+1+x)) 表示三种转移方式,但是求出来的 (F) 显然不是正确答案,因为会有从负数幂的贡献是应该减掉的。

    那么我们就考虑减掉它,实际上和解法一相同,(f(x)-f(x+2)) 相当于减去了错解,那么减完之后就是答案了。

    因为每次要倍长多项式,使用快速幂一样的方式卷就可以了。根据主定理,时间复杂度 (O(nlog n))

    考场上有部分分,模数为 (998244353),那么正解只需要改成任意模数多项式乘法就行了。

    代码

    注意,此代码不可 AC 此题,仅在模数为 (998244353) 时正确。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cctype>
    #include<cstdlib>
    using namespace std;
    inline int read(){
    	int x=0,w=0;char c=getchar();
    	while(!isdigit(c)) w|=c=='-',c=getchar();
    	while(isdigit(c)) x=x*10+(c^48),c=getchar();
    	return w?-x:x;
    }
    namespace star
    {
    	const int maxn=2e6+10,mod=998244353,ge=3,gi=998244354/3;
    	inline int fpow(int a,int b){int ans=1;for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod;return ans;}
    	struct NTT{
    		int r[maxn],lim;
    		inline void getr(int li){lim=li;for(int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)*(lim>>1));}
    		inline void operator () (int *a,int type) const {
    			for(int i=0;i<lim;i++) if(i<r[i]) swap(a[i],a[r[i]]);
    			for(int mid=1;mid<lim;mid<<=1){
    				int rt=fpow(type==1?ge:gi,(mod-1)/(mid<<1));
    				for(int r=mid<<1,j=0;j<lim;j+=r){
    					int p=1;
    					for(int k=0;k<mid;k++,p=1ll*p*rt%mod){
    						int x=a[j+k],y=1ll*p*a[j+k+mid]%mod;
    						a[j+k]=(x+y)%mod,a[j+k+mid]=(x-y+mod)%mod;
    					}
    				}
    			}
    			if(type==-1) for(int p=fpow(lim,mod-2),i=0;i<lim;i++) a[i]=1ll*a[i]*p%mod;
    		}
    	}ntt;
    	int n;
    	int a[maxn],ans[maxn];
    	inline void work(){
    		n=read();read();
    		int Lim=4,lim=2;
    		a[0]=a[1]=a[2]=ans[0]=1;
    		int x=n,Len=3,len=1;
    		while(x){
    			static int res[maxn],tmp[maxn];
    			if(x&1){
    				for(int i=0;i<Lim;i++) res[i]=a[i];
    				for(int i=Lim;i<Lim+lim;i++) res[i]=0;
    				for(int i=0;i<lim;i++) tmp[i]=ans[i];
    				for(int i=lim;i<Lim+lim;i++) tmp[i]=0;
    				len+=Len;lim=Lim;
    				while(lim<len) lim<<=1;
    				ntt.getr(lim<<1);
    				ntt(res,1),ntt(tmp,1);
    				for(int i=0;i<lim<<1;i++) tmp[i]=1ll*res[i]*tmp[i]%mod;
    				ntt(tmp,-1);
    				for(int i=0;i<lim;i++) ans[i]=tmp[i];
    			}
    			for(int i=0;i<Lim;i++) res[i]=a[i];
    			for(int i=Lim;i<Lim<<1;i++) res[i]=0;
    			Lim<<=1;Len<<=1;
    			for(int i=Lim;i<Lim<<1;i++) res[i]=0;
    			ntt.getr(Lim<<1);
    			ntt(res,1);
    			for(int i=0;i<Lim<<1;i++) res[i]=1ll*res[i]*res[i]%mod;
    			ntt(res,-1);
    			for(int i=0;i<Lim;i++) a[i]=res[i];
    			x>>=1;
    		}
    		int l=read(),r=read();
    		for(int i=n;i<n<<1;i++) ans[i]=(ans[i]-ans[i+2]+mod)%mod;
    		int Ans=0;
    		for(int i=n+l;i<=n+r;i++) Ans=(Ans+ans[i])%mod;
    		printf("%d
    ",Ans);
    	}
    }
    signed main(){
    	star::work();
    	return 0;
    }
    
  • 相关阅读:
    [Javascript] 面向对象编程思想
    [Javascript] “||”和“&&”的灵活运用
    [Java] HashMap、TreeMap、Hashtable排序
    [Java] 多个Map的性能比较(TreeMap、HashMap、ConcurrentSkipListMap)
    [Java] 集合类(List、Set、Map的基本使用)
    [Java] Map 集合类简介
    [Javascript,JSON] JQuery处理json与ajax返回JSON实例
    [PHP] Eclipse开发PHP环境配置
    nginx的 CPU参数worker_processes和worker_cpu_affinity使用说明
    【HTTP 2】启用 HTTP 2(Starting HTTP/2)
  • 原文地址:https://www.cnblogs.com/BrotherHood/p/14516337.html
Copyright © 2020-2023  润新知