[Lydsy2017省队十连测]商店购物
SOL:
我们可以前面写背包,后面组合数。
#include<bits/stdc++.h> #pragma GCC optimize("-O2") #define mo 1000000007 #define N 10000007 #define LL long long using namespace std; #define sight(x) ('0'<=x&&x<='9') inline void read(LL &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar())x=x*10+c-48; } void write(int x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);} inline void writeln(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); } inline void writel(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); } LL fac[N],sum[N],f[N],n,m,k,last,x,ans; inline LL qsm(LL x,LL y=mo-2) { static LL anw; for (anw=1,x%=mo;y;y>>=1,x=x*x%mo) if (y&1) anw=anw*x%mo; return anw; } inline LL C(LL x,LL y) { if (y==0) return 1; x+=y; y--; return fac[x-1]*qsm(fac[y])%mo*qsm(fac[x-y-1])%mo; } signed main () { // freopen("a.in","r",stdin); read(m); read(n); read(k); fac[0]=1; for (int i=1;i<N;i++) fac[i]=fac[i-1]*i%mo; for (int i=0;i<=5007;i++) sum[i]=1; for (int t=1;t<=n;t++) { read(x); last+=x; for (int i=0;i<=last;i++) f[i]=sum[i]-(i>x?sum[i-x-1]:0),f[i]%=mo,f[i]=(f[i]+mo)%mo; sum[0]=f[0]; for (int i=1;i<=last+307;i++) sum[i]=sum[i-1]+f[i],sum[i]%=mo; } if (m!=n) for (int i=0;i<=min(last,k);i++) ans=ans+f[i]*C(k-i,m-n)%mo,ans%=mo; else ans=f[min(last,k)]; writeln(ans); return 0; }