码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 6397(2018多校第8场1001) Character Encoding 容斥

时间:2018-08-15 22:59:10      阅读:351      评论:0      收藏:0      [点我收藏+]

标签:cas   cpp   names   bit   方案   oid   nbsp   can   时代   

听了杜教的直播后知道了怎么做,有两种方法,一种构造函数(现在太菜了,听不懂,以后再补),一种容斥原理。

知识补充1:若x1,x2,.....xn均大于等于0,则x1+x2+...+xn=k的方案数是C(k+m-1,m-1)种(貌似紫书上有,记不太清了)。

知识补充2:若限制条件为n(即x1,x2....xn均小于n,假设有c个违反,则把k减掉c个n(相当于把c个超过n的数也变成大于等于0的),就可以套用知识1的公式了。

则最后的答案为sum( (-1)^c * C(m , c) * C(m-1+k-n*c , m-1) );

这个题貌似要预处理出乘法逆元,不然会TLE。我的lucas定理做法超时了。。。

借鉴了杜教链接中的代码,O(n)时间预处理:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL mod=998244353;
const int maxn=203000;
LL f[maxn],fv[maxn];//f是阶乘,fv是乘法逆元 
LL quick_power(LL a,LL b){
	LL ans=1;
	for(;b;b>>=1){
		if(b&1)ans=ans*a%mod;
		a=a*a%mod;
	}
	return ans;
}
void init(){//初始化 
	f[0]=1;
	for(LL i=1;i<maxn;i++)
		f[i]=(f[i-1]*i)%mod;
	fv[maxn-1]=quick_power(f[maxn-1],mod-2);
	for(LL i=maxn-1;i>0;i--){
		fv[i-1]=fv[i]*i%mod;
	}
}
LL C(LL n,LL m){//这样可以O(1)计算出组合数 
	if(n<0||m<0||n<m)return 0;
	return f[n]*(fv[m])%mod*fv[n-m]%mod;
}
int main(){
	LL n,m,k,ans;
	int T;
	init();
	scanf("%d",&T);
	while(T--){
		scanf("%lld%lld%lld",&n,&m,&k);
		LL ans=0;
		for(int c=0;c*n<=k;c++){//容斥 
			if(c&1)ans=(ans-C(m,c)*C(k-c*n-1+m,m-1)%mod+mod)%mod;
			else ans=(ans+C(m,c)*C(k-c*n-1+m,m-1)%mod)%mod;
		}
		printf("%lld\n",ans);
	}
} 

  还是附上超时代码,单次查询是O(lgn)的,如果查询次数比较少可以用这个,可以当作模板。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL mod=998244353;
LL power(LL a){
	if(a&1)return -1;
	return 1;
}
LL quick_power(LL a,LL b){
	LL ans=1%mod;
	while(b){
		if(b&1){
			ans=ans*a%mod;
			b--;
		}
		b>>=1;
		a=a*a%mod; 
	}
	return ans;
} 
LL C(LL n,LL m){
	if(m>n)return 0;
	LL ans=1;
	for(int i=1;i<=m;i++){
		LL a=(n+i-m)%mod;
		LL b=i%mod;
		ans=ans*(a*quick_power(b,mod-2)%mod)%mod;
	}
	return ans;
}
LL lucas(LL n,LL m){
	if(m==0)return 1;
	return C(n%mod,m%mod)*lucas(n/mod,m/mod)%mod;
}
int main(){
	LL n,m,k,ans;
	int T;
	scanf("%d",&T);
	while(T--){
		ans=0;
		scanf("%lld%lld%lld",&n,&m,&k);
		for(LL i=0;i*n<=k;i++){
			ans=(ans+(((power(i)*lucas(m,i))%mod)*lucas(m-1+k-n*i,m-1))%mod)%mod;
		}
		printf("%lld\n",ans);
	}
}  

  

 

HDU 6397(2018多校第8场1001) Character Encoding 容斥

标签:cas   cpp   names   bit   方案   oid   nbsp   can   时代   

原文地址:https://www.cnblogs.com/pkgunboat/p/9484230.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!