美味糖果[一道简单的DP]

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

 

posted @ 2020-02-11 11:37  神犇(shenben)  阅读(255)  评论(0编辑  收藏  举报