atcoder abc 159:F - Knapsack for All Segments(思維 + 貢獻 + dp)

在這裏插入圖片描述


有一個 n3n^3 的樸素做法,對每個區間 進行 dp,顯然是通過不了的,且轉移複雜度爲 O(1),沒有優化的空間,得考慮從其它角度切入這題。

對於某個解,最左邊的數字的下標爲 xx,最右邊的數字的下標爲 yy,這組解對答案的貢獻爲:x(ny+1)x * (n - y + 1),考慮枚舉每個數字作爲一組解的最右邊的點,對於第 i 個數字,需要知道前 i1i-1個數字,每種權值和爲 sa[i]s - a[i] 的方案的最左邊的數字的下標和,這個可以 dp 得到,設 dp[i][v]dp[i][v] 表示前 ii 個數字,權值和爲 v 的各種方案中,最左邊的數字的下標和,顯然 dp[i][v]=dp[i1][v]+dp[i1][va[i]]dp[i][v] = dp[i - 1][v] + dp[i - 1][v - a[i]],當 v=a[i]v = a[i] 時,dp[i][a[i]]+=idp[i][a[i]] += i

第一維可以滾動,則每個數字作爲最右邊的數時對答案的貢獻爲:(ni+1)dp[sa[i]](n - i + 1) * dp[s - a[i]]

注意特判轉移時, s=a[i]s = a[i] 的情況,這時最左最右均爲 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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章