【背包】【组合数学】BZOJ5215 [Lydsy2017省队十连测]商店购物

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/88015310

分析:

背包+组合数学

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 310
#define MAXM 10000010
#define MOD 1000000007
using namespace std;
typedef long long ll;
ll dp[2][MAXN*MAXN],sum[2][MAXN*MAXN];
ll fac[MAXM],ifac[MAXM],ans;
ll fsp(ll x,int y){
	ll res=1;
	while(y){
		if(y&1)
			res=res*x%MOD;
		x=x*x%MOD;
		y>>=1;
	}
	return res;
}
ll C(int n,int m){
//	PF("[%d %d]\n",n,m);
	return fac[n]*ifac[m]%MOD*ifac[n-m]%MOD;
}
int w[MAXN];
int main(){
//	freopen("shopping.in","r",stdin);
//	freopen("shopping.out","w",stdout);
	int n,m,k;
	SF("%d%d%d",&n,&m,&k);
	fac[0]=1;
	for(int i=1;i<=10000000;i++)
		fac[i]=fac[i-1]*i%MOD;
	ifac[10000000]=fsp(fac[10000000],MOD-2);
	for(int i=10000000;i>=1;i--)
		ifac[i-1]=ifac[i]*i%MOD;
	for(int i=1;i<=m;i++)
		SF("%d",&w[i]);
	dp[0][0]=1;
	int now=0;
	int tot=0;
	for(int i=1;i<=m;i++){
		now^=1;
		dp[now][0]=1;
		tot+=w[i];
		sum[now^1][0]=1;
		for(int j=1;j<=tot;j++){
			sum[now^1][j]=(sum[now^1][j-1]+dp[now^1][j])%MOD;
			if(j>w[i])
				dp[now][j]=(sum[now^1][j]-sum[now^1][j-w[i]-1]+MOD)%MOD;
			else
				dp[now][j]=sum[now^1][j];
		}
	}
	if(n==m){
		if(k>tot)
			PF("0");
		else
			PF("%lld",dp[now][k]);
		return 0;
	}
	for(int i=0;i<=min(k,tot);i++)
		ans=(ans+dp[now][i]*C(k-i+n-m-1,n-m-1)%MOD)%MOD;
	PF("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/88015310