版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/88890897
title
analysis
-
30 分做法
对于 20% 的数据, 。
考虑 ,设 表示考虑了前 家商店,消费总和为 的
方案数,暴力枚举每家商店消费了多少钱即可。
时间复杂度 。 -
50 分做法
对于 50% 的数据, 。
考虑优化 DP 转移的复杂度,转移显然可以用 优化到
。
时间复杂度 。 -
70 分做法
对于 70% 的数据, 。
假如没有上限,那么就是简单的排列组合问题,用隔板法即
可算出方案数为 。
考虑容斥,暴力枚举哪些商店必然超过了限制,而不关心其
它商店,那么把 减去这些商店的上限 之和,即可求出
贡献。
时间复杂度 。 -
100 分做法
注意到暴力枚举哪些商店必然超过了限制时,我们事实上只
关心选的商店的上限之和以及选的商店个数的奇偶性。
考虑 ,设 表示考虑了前 个商店,目前选的商店的
上限 之和为 时的贡献。
如果这个商店不选,那么有 ,否则有
。
。
时间复杂度 。
code
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int inf=1e7+10;
const int maxm=310;
const int maxn=1e5+10;
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
inline int Quick_power(int a,int b)
{
int ans=1;
while (b)
{
if (b&1)
ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ans;
}
int fac[inf],inv[inf];
inline int C(int x,int y)//计算组合数
{
if (y==-1) return x==-1;
return 1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;
}
int w[maxm],f[2][maxn];
int main()
{
int n,m,k;
read(n);read(m);read(k);
for (int i=1; i<=m; ++i)
read(w[i]);
//统计出前i个商店消费0...j-1的方案数之和
for (int i=1; i<=maxn-10; ++i)
f[0][i]=1;
for (int i=1; i<=m; ++i)
{
int o=i&1;
for (int j=1; j<=maxn-10; ++j)
{
f[o][j]=f[o][j-1];
(f[o][j]+=(f[o^1][j]-f[o^1][max(j-w[i]-1,0)]+mod)%mod)%=mod;
}
}
int o=m&1;
for (int i=maxn-10; i>=0; --i)
f[o][i]=(f[o][i]-f[o][i-1])%mod;
//计算阶乘
fac[0]=1;
for (int i=1; i<=k+n; ++i)
fac[i]=1ll*fac[i-1]*i%mod;
//计算逆元
inv[k+n]=Quick_power(fac[k+n],mod-2);
for (int i=k+n-1; i>=0; --i)
inv[i]=1ll*inv[i+1]*(i+1)%mod;
//统计答案
int ans=0;
for (int i=1; i<=min(k+1,maxn-10); ++i)
{
ans+=1ll*f[o][i]*C(k-i+n-m,n-m-1)%mod;
ans%=mod;
}
if (ans<0) ans+=mod;
printf("%d\n",ans);
return 0;
}
summary
考试的时候,想到了组合数,然而只会没有上限的那种。没想到DP。??我也很奇怪,为啥没想到DP。然后不知道怎么回事,评测的时候,全T了。还是知识点掌握的不够熟练。