【题目】
BZOJ
有
n
n
n个非负整数,其中前
m
m
m个不超过
w
i
w_i
wi,已知所有数字和为
k
k
k,求方案数。
m
,
w
i
≤
300
,
n
,
k
≤
5
×
1
0
6
m,w_i\leq 300,n,k\leq 5\times 10^6
m,wi≤300,n,k≤5×106
【解题思路】
前
m
m
m个数可以背包算出方案数,后面的数字用隔板法可以直接求出方案。
背包的时候可以发现贡献的是连续一段,所以做一个差分即可。
设
m
,
w
m,w
m,w同阶,复杂度
O
(
n
+
m
3
)
O(n+m^3)
O(n+m3)
神tm还卡常,预处理需要处理刚好够才能过。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+100,mod=1e9+7;
int n,m,K,mx,t;
ll ans,f[N],fac[N],ifac[N];
ll qpow(ll x,ll y){ll res=1;for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;return res;}
ll C(int x,int y){if(x<0)return 1;if(y<0||x<y)return 0;return fac[x]*ifac[y]%mod*ifac[x-y]%mod;}//wrong because nopd n<0
void up(ll &x,ll y){x+=y;if(x>=mod)x-=mod;}
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ5215.in","r",stdin);
freopen("BZOJ5215.out","w",stdout);
#endif
scanf("%d%d%d",&n,&m,&K);f[0]=1;t=m*300;
fac[0]=1;for(int i=1;i<=n+K;++i)fac[i]=fac[i-1]*i%mod;
ifac[n+K]=qpow(fac[n+K],mod-2);for(int i=n+K-1;~i;--i)ifac[i]=ifac[i+1]*(i+1)%mod;
for(int i=1,x;i<=m;++i)
{
scanf("%d",&x);mx+=x;
for(int j=mx-x;~j;--j) up(f[j+x+1],mod-f[j]);
for(int j=1;j<=t;++j) up(f[j],f[j-1]);
}
//for(int i=0;i<=mx;++i) printf("%lld ",f[i]); puts("");
n-=m;
for(int i=0;i<=K;++i) up(ans,f[i]*C(n+(K-i)-1,n-1)%mod);
printf("%lld\n",ans);
return 0;
}