Character Encoding(hdu 6397 组合数容斥)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6397
题意:M个位置,每个位置放不超过N的数,求是这些位置加起来的和为K的方案数?
如果没有“每个位置放不超过N的数”这样的限制,那就是很经典的隔板法了
普通的隔板法就是每个位置的数都要大于0,就是
而可以为0的隔板法就是考虑极端的情况,有
个位置都是
,这个时候在这
个位置都放一个物品,相当于总的物品有
个,于是就变成了
对容斥理解不深入T_T,当时也想到这样:0个位置超了-1个位置超了+2个位置超了-3个位置超了….
但是我还想的是假如一个位置只超了一个物品,或者超了两个物品,或者超了三个物品…怎么办?这样感觉情况好多啊,但是其实不用考虑这些,我也不理解为什么不考虑这些,只能感觉这些情况会被容斥干掉。。。
这道题和51nod上的这道1269 Devu and Flowers 很类似,这个就是每个位置限制的数不一样
然后这道题我一直wa,以为我是组合数模板有问题,后来找到原因是因为 中的 比 大了,要返回
#include"bits/stdc++.h"
#define C(n,m) ((long long)fac[(n)]*invf[(m)]%MOD*invf[(n)-(m)]%MOD)
using namespace std;
typedef long long LL;
const int maxn=2e5+5;
const LL MOD=998244353;
LL ksm(LL a,LL b,LL mod)
{
LL res=1,base=a;
while(b)
{
if(b&1)res=(res*base)%mod;
base=(base*base)%mod;
b>>=1;
}
return res;
}
LL fac[maxn]={1,1},invf[maxn]={1,1};
void InitFac(int n)
{
for(int i=2;i<=n;i++)fac[i]=fac[i-1]*i%MOD;
invf[n]=ksm(fac[n],MOD-2,MOD);
for(int i=n-1;i>=2;i--)invf[i]= invf[i+1]*(i+1)%MOD;
}
int main()
{
InitFac(maxn-5);
LL T,N,M,K;
cin>>T;
while(T--)
{
cin>>N>>M>>K;
LL ans=0;
for(LL c=0;c*N<=K;c++)
{
if(c>M)continue;//如果c大于M就是0
LL tp=C(M,c)*C(K-c*N+M-1,M-1)%MOD;
if(c&1LL)ans-=tp;
else ans+=tp;
ans=(ans%MOD+MOD)%MOD;
}
cout<<ans<<endl;
}
}
Taotao Picks Apples(hdu 6406)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6406
参考这位童鞋的博客:http://www.cnblogs.com/zzqc/p/9490772.html
思路:就是处理一个前缀
表示从
的答案,后缀
表示
的答案
加入现在修改
这个位置修改成
,设
是
最大值的下标,那么前半段的答案就是
,因为我们是按照贪心来取数的,比上一次大的就一定会取,而不是求
,而后半段是要找第一个比
大的数,怎么样快速找到 第一个大的数呢?方法很多,这里是二分来找的