I. 试题I:美味糖果 25'
描述
由于疫情缘故,wlxsq家里还剩下超多年货,没有吃完。
为了简化问题,假设wlxsq家里还剩N种年货,每种年货Ai包,同一种年货中每一包都是一样的。
现在wlxsq准备返杭了,他想从N种年货中挑不超过K包年货带返杭。wlxsq想知道他总共有多少种选择方案?
输入
第一行输入两个整数N,K,含义如题目描述。
第二含输入N个整数 Ai,表示每一种年货的数量。
输出
输出总共方案数,结果对998244353取模。
样例
输入
3 1 2 2 2
输出
4
输入
8 13 1 2 3 4 5 6 7 8
输出
65044
提示
【样例1解释】
总共有4种方案,对应每一种年货的选择如下:(1,0,0),(0,1,0),(0,0,1),(0,0,0)
【评测用例规模与约定】
对于40%的数据,2<=N<=10,
对于100%的数据,2<=N<=1000,Ai,K<=10^5
题解
1、$dp[i][j]$:前i种年货取j包的方案数
2、$dp[i][j] = sum_{k = 0}^{Ai} dp[i - 1][j - k], j >= k$
最后计算 $sum_{j = 0}^{K}dp[n][j]$即可
优化1:使用滚动数组,保证内存不炸~
优化2:使用前缀和,计算出$sum_{k = 0}^{Ai} dp[i - 1][j - k]$的值。
#include<iostream> using namespace std; const int N=1e5+5; const int mod=998244353; int n,now,K,ans,a[N],f[2][N],s[2][N]; int main(){ scanf("%d%d",&n,&K); for(int i=1;i<=n;i++) scanf("%d",a+i); for(int i=0;i<=K;i++) s[0][i]=1; f[0][0]=1; for(int i=1;i<=n;i++){ now^=1; for(int j=0,t;j<=K;j++){ t=max(j-a[i]-1,-1); f[now][j]=(s[now^1][j]-(~t?s[now^1][t]:0)+mod)%mod; s[now][j]=((j?s[now][j-1]:0)+f[now][j])%mod; } } for(int j=0;j<=K;j++) (ans+=f[now][j])%=mod; cout<<ans; return 0; }