• 唱、跳、rap 和篮球「TJOI2019」


    题意

    有若干个人,喜欢唱跳rap篮球,数量给定。排成一行,如果有连续四个人分别喜欢唱跳rap篮球,那么不合法。求总方案数。


    思路

    容易想到枚举连续情况,然后删去,但是这样无法解决连续情况外的连续。

    所以考虑容斥。

    每次容斥的时候如果暴力求出方案会到(O(n^3)),所以可以用一个小trick优化一下:枚举哪些部分唱跳,哪些部分rap篮球,然后(O(1))计算区内方案数。(此处是否选择唱跳并不重要,因为是对称的)

    代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    namespace StandardIO {
    
    	template<typename T>inline void read (T &x) {
    		x=0;T f=1;char c=getchar();
    		for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
    		for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
    		x*=f;
    	}
    
    	template<typename T>inline void write (T x) {
    		if (x<0) putchar('-'),x*=-1;
    		if (x>=10) write(x/10);
    		putchar(x%10+'0');
    	}
    
    }
    
    using namespace StandardIO;
    
    namespace Project {
    	#define int long long
    	
    	const int N=1001;
    	const int MOD=998244353;
    	
    	int n,a,b,c,d,ans;
    	int C[N][N],sum[N][N];
    	
    	inline int query (int i,int l,int r) {
    		if (r<l) return 0;
    		if (l<=0) return sum[i][r];
    		return (sum[i][r]-sum[i][l-1]+MOD)%MOD;
    	}
    
    	inline void MAIN () {
    		read(n),read(a),read(b),read(c),read(d),a=min(n,a),b=min(n,b),c=min(n,c),d=min(n,d);
    		for (register int i=0; i<=1000; ++i) {
    			C[i][0]=sum[i][0]=1;
    			for (register int j=1; j<=i; ++j) {
    				C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
    			}
    			for (register int j=1; j<=1000; ++j) {
    				sum[i][j]=(sum[i][j-1]+C[i][j])%MOD;
    			}
    		}
    		for (register int i=0; i<=n/4; ++i) {
    			int res=0,left=n-i*4;
    			for (register int j=0; j<=left; ++j) {
    				int rap=left-j;
    				res=(res+C[left][j]*query(j,j-a,b)%MOD*query(rap,rap-c,d)%MOD)%MOD;
    			}
    			res=(res*C[i+left][i])%MOD;
    			if (i&1) ans=(ans-res+MOD)%MOD;
    			else ans=(ans+res)%MOD;
    			--a,--b,--c,--d;
    			if (a<0||b<0||c<0||d<0) break;
    		}
    		write(ans);
    	}
    	
    	#undef int
    }
    
    int main () {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	Project::MAIN();
    }
    
    
  • 相关阅读:
    (转)描述线程与进程的区别?
    Python学习笔记:ceil、floor、round、int取整
    Python学习笔记:SQL中group_concat分组合并操作实现
    Python学习笔记:pd.rank排序
    函数声明
    Dictionary 介绍
    Tuple介绍
    List介绍
    DataGridView 如何退出 编辑状态
    C#实现打印与打印预览功能
  • 原文地址:https://www.cnblogs.com/ilverene/p/11592841.html
Copyright © 2020-2023  润新知