[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;
}

 

posted @ 2018-06-02 20:55  泪寒之雪  阅读(185)  评论(0编辑  收藏  举报