题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6397
这周多校完全身败名裂。。。。
题意: 求 x1+x2……+xm=k 0<=xi<n 的方案数
看下这边orzhttps://blog.csdn.net/m0_37286282/article/details/78869512
就是经典的有限制的方程整数解的问题。。。
在没有限制的情况下,用插板法答案就是 C(k+m-1,m-1)
现在考虑至少有p个数突破了限制的情况,就是先取p个n 出来,剩下的数没有限制的分成m份,然后再把p个n分到这m份中的p个数里头去就能保证至少有p个数突破了限制
令F(x)表示至少有x个数突破限制的方案数
那么我们现在要求突破限制的方案总数,根据容斥原理就是F(1)-F(2)+F(3)..........
总的方案数看成C(m,0)*C(k+m-1,m-1)我们的答案化简下就是
另外的一种做法是母函数orz
我们第一位相当于(x^0+x^1+x^2......+x^n-1)
一共有m位那么就是(x^0+x^1+x^2......+x^n-1)^m 我们的答案就是其中x^k的系数
代码是容斥orz
#include<bits/stdc++.h>
#define ll long long
#define mod 998244353
#define maxn 203000
using namespace std;
ll f[maxn],fv[maxn];
ll q_pow(ll a,ll b){
ll ans=1;
while(b){
if (b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void init(){
f[0]=1;
for (ll i=1;i<maxn;i++)
f[i]=(f[i-1]*i)%mod;
fv[maxn-1]=q_pow(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){
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;
init();
int t;
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);
}
}
我是真的料理上手orz