转载:转自洛谷
内存限制:250MB
思路: dp+滚动数组优化+前缀和优化
将一个堆的状态分为两种:靠到左边、未靠到左边
具体转移方程见链接。
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
using namespace std;
typedef long long ll;
const int N = 7e3+10;
const int mod = 998244353;
ll d[N];
ll f[2][N];//f hi-1 >= hi-di
ll g[2][N];//g hi < hi-di
int main()
{
IOS;
ll n,m;
cin>>n>>m;
_for(i,1,n)
cin>>d[i];
//第一堆
_for(i,0,m) f[1][i] = i+1;
_for(i,2,n)
{
//01滚动数组
int p = i&1;
int q = p^1;
_for(j,0,m)
{
ll l = max(0ll,j-d[i]);
ll r = min(m,j+d[i-1]);
//巧妙利用前缀和
f[p][j] =( ( f[q][m] + g[q][r]) - (l? (f[q][l-1] + g[q][l-1] ) :0) + ( j ? f[p][j-1]:0) +mod) %mod;
g[p][j] = ((j ? g[p][j-1] : 0 ) + (l? ( f[q][l-1] +g[q][l-1] ):0 )) %mod;
}
}
cout<< ( f[n&1][m]+g[n&1][m] ) % mod <<endl;
}