BZOJ 4559: [JLoi2016]成绩比较【计数dp,容斥,组合数

听说王队长的题解特别妙【摔


好吧的确挺♂妙


先yy出求每个人相对排名不同的方案数(用f来记录)

因为是有顺序的……所以不能直接容斥……就用 f[i] 表示 有刚好 i 个人被碾压的方案数 , 再用 至少 i 个人被碾压的方案数 减掉不合法的

看代码吧,还是挺好懂的,或者前两篇题解也写的很稳【王队长的题解啊exciting


然后求在每种排名下 分数不同的方案数……自己yy一下 C一C……xjb搞就完啦【真的不是忙着回家懒得码字了【滑稽

嘤……jq爸爸的容斥这么强于是Flaze莫名入了计数dp的坑,虽然因为太弱被jq 裱上了天2333


哼 我觉得jq马上就能上传说233333


代码↓

#include
#define MAXN 105
#define MOD 1000000007ll
using namespace std;	int n,m,K;
inline int read() {
	register int ch = getchar();
	while(!isdigit(ch))	ch = getchar();
	register int rtn = 0;
	while(isdigit(ch))	rtn = rtn*10 + ch - '0' , ch = getchar();
	return rtn;
}

inline long long pow_(long long d,int c) {
	long long rtn = 1 ;
	for(;c;c>>=1,d = d*d%MOD)
		if(c&1)
			(rtn *= d) %= MOD;
	return rtn ;
}

long long u[MAXN] , rk[MAXN] , max_rank = 0 ;
long long fac[MAXN] , inv[MAXN];

long long f[MAXN] , g[MAXN];

inline long long C(int a,int b) {return fac[a]*inv[b] %MOD *inv[a-b] %MOD;}
inline long long A(int a,int b) {return fac[a]*inv[a-b] %MOD;}

int main() {
	//freopen("1.in","r",stdin);
	n = read() , m = read() , K = read();
	for (int i=1;i<=m;++i)	u[i] = (long long) read();
	for (int i=1;i<=m;++i)	
		max_rank = max( max_rank , rk[i] = (long long) read() );

	//printf("max = %lld\n",max_rank);
	if(K> n - max_rank)	return puts("0"),0;

	fac[0] = 1 , inv[0] = 1;
	for (int i=1;i<=100;++i)
		fac[i] = fac[i-1] * i % MOD , inv[i] = pow_(fac[i],MOD-2);

	for(int i=n-max_rank;i;--i){
		f[i] = C(n-1,i);
		for(int j=1;j<=m;++j)	( f[i] *= C(n-i-1,rk[j]-1) ) %= MOD;
		for(int j=n-max_rank;j^i;--j)
			( f[i] += MOD - C(j,i)*f[j]%MOD ) %= MOD;
	}

	//printf("%lld\n",f[K]);

	long long tmp = 1;
	for(int i=1;i<=m;++i){
		memset(g,0,sizeof g);
		g[0] = u[i];
		long long bbb = u[i] + 1 ;
		long long base = bbb * bbb % MOD;
		for(int k=1;k<=n;++k) {
			g[k] = base - 1 ;
			long long mns = 0;
			for(int j=0;j


你可能感兴趣的:(OI,BZOJ,计数dp,组合数学,容斥)