Description
有n+m种物品,前n种物品的大小为1,后m种物品的大小为2,每种物品都有无限个
求用着n+m种物品放满大小为k的背包的方案数,答案对p取模
n,m<=1e5,k<=1e12,p<=1e6,保证p为质数
Solution
题解被samjia打爆了=w=
答案的生成函数显然就是
题解给出了一个式子:
有了这条式子很好做,不过其实原式直接可以化成
都是O(n+m)的,不过那个式子可能有用记一下问题不大
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,m,p,ty,fact[N],inv[N];
ll k;
int pwr(int x,int y) {
int z=1;
for(;y;y>>=1,x=(ll)x*x%p)
if (y&1) z=(ll)z*x%p;
return z;
}
int C(ll m,ll n) {
if (m<n) return 0;
if (m<p&&n<p) return (ll)fact[m]*inv[n]%p*inv[m-n]%p;
return (ll)C(m/p,n/p)*C(m%p,n%p)%p;
}
int main() {
freopen("luckye.in","r",stdin);
freopen("luckye.out","w",stdout);
for(scanf("%d",&ty);ty;ty--) {
scanf("%d%d%lld%d",&n,&m,&k,&p);
fact[0]=1;fo(i,1,p-1) fact[i]=(ll)fact[i-1]*i%p;
inv[p-1]=pwr(fact[p-1],p-2);fd(i,p-2,0) inv[i]=(ll)inv[i+1]*(i+1)%p;
int ans=0;
fo(i,0,n) if (!((k-i)&1)) (ans+=(ll)C(n,i)*C((k-i)/2+n+m-1,n+m-1)%p)%=p;
printf("%d\n",ans);
}
return 0;
}