题解 AT4534 【Candies】

· · 题解

设 f[i][j] 表示 1 到 i 里一共分配了 j 的方案数。

那么枚举第 i 选的个数 l\in[0,a[i]],易得转移方程

f[i][j]=f[i][j]+\sum_{l=0}^{a[i]}f[i-1][j-l]

时间复杂度 \mathcal{O(n^3)},过不了。

考虑前缀和优化。

设 pre[i][j] 表示 \sum\limits_{j=1}^{n}f[i][j]。

那么转移方程可以化简为

f[i][j]=f[i][j]+pre[i][\ j\ ]-pre[i][\ (j-a[i])-1\ ] 时间复杂度 $\mathcal{O(n^2)}$。 ```cpp #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define int long long inline int read(){ register int x=0,f=0,ch=getchar(); while('0'>ch||ch>'9')f^=ch=='-',ch=getchar(); while('0'<=ch&&ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar(); return f?-x:x; } const int MAX=105,MAXN=1e5+5,P=1e9+7; int n,k; int f[MAX][MAXN],a[MAX],l,r,pre[MAX][MAXN]; signed main(){ n=read(),k=read(); for(register int i=1;i<=n;++i)a[i]=read(); f[0][0]=pre[0][0]=1; for(register int i=1;i<=k;++i)pre[0][i]+=pre[0][i-1]; for(register int i=1;i<=n;++i){ for(register int j=0;j<=k;++j){ l=max(0LL,j-a[i]),r=j; f[i][j]=(((f[i][j]+pre[i-1][r])%P-pre[i-1][l-1])+P)%P; } pre[i][0]=1; for(register int j=1;j<=k;++j)pre[i][j]=(pre[i][j-1]+f[i][j])%P; } printf("%lld\n",f[n][k]); return 0; } ```