有一個 的樸素做法,對每個區間 進行 dp,顯然是通過不了的,且轉移複雜度爲 O(1),沒有優化的空間,得考慮從其它角度切入這題。
對於某個解,最左邊的數字的下標爲 ,最右邊的數字的下標爲 ,這組解對答案的貢獻爲:,考慮枚舉每個數字作爲一組解的最右邊的點,對於第 i 個數字,需要知道前 個數字,每種權值和爲 的方案的最左邊的數字的下標和,這個可以 dp 得到,設 表示前 個數字,權值和爲 v 的各種方案中,最左邊的數字的下標和,顯然 ,當 時,
第一維可以滾動,則每個數字作爲最右邊的數時對答案的貢獻爲:
注意特判轉移時, 的情況,這時最左最右均爲 i
代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e3 + 10;
const int mod = 998244353;
typedef long long ll;
#define lowbit(i) (i & (-i))
ll sum[maxn];
int n,m,k,a[maxn],s,dp[maxn];
int main() {
scanf("%d%d",&n,&s);
for (int i = 1; i <= n; i++)
scanf("%d",&a[i]);
int ans = 0;
for (int i = 1; i <= n; i++) {
if (s > a[i]) ans = (ans + 1ll * dp[s - a[i]] * (n - i + 1)) % mod;
else if (s == a[i]) ans = (ans + 1ll * i * (n - i + 1)) % mod;
for (int j = s; j >= a[i]; j--)
dp[j] = (dp[j] + dp[j - a[i]]) % mod;
dp[a[i]] = (dp[a[i]] + i) % mod;
}
printf("%d\n",ans);
}