codeforces1129D. Isolation分塊優化Dp

codeforces1129D. Isolation

題目連接

分析

題目大意:給你一個序列,上面每個位置有一種顏色,求把這個序列分割成若干段,使得每一段的只出現一次的顏色個數不超過kk個,求方案數。
一個顯然的1D/1DDp1D/1DDp
f(i)=j=1if(j1)[cnt(j,i)k]f(i)=\sum_{j=1}^i f(j-1)[cnt(j,i) \le k]
重點在於,cnt(j,i)cnt(j,i)難以計算。
考慮如何形式化這個問題。
定義數組bb,如果iji\to jaja_j顏色第一次出現,那麼bj=1b_j=1,第二次出現bj=1b_j=-1,否則bj=0b_j=0
那麼cnt(j,i)=k=jibkcnt(j,i)=\sum_{k=j}^ib_k
這個時候考慮ii+1i\to i+1的過程。
我們發現,有一個bpb_p111\to -1,有一個bqb_q10-1\to0
考慮cnt(j,i+1)cnt(j,i+1)相對於cnt(j,i)cnt(j,i)的變化。
[p+1,i]+1,[q+1,p]1[p+1,i]+1,[q+1,p]-1其餘不變。
我們現在要做的事情就是,把當前cntkcnt\le k的所有ff加起來。
考慮分塊。對於每一塊,記錄每個vaksvak_s表示cnt=scnt=s的所有ff之和。
那麼每一塊,做區間修改是考慮打標記。
也就是說,valsval_s實際上表示的是cnt=s+tagxcnt=s+tag_x的所有ff之和。
考慮tagxtag_x變化的時候對答案的貢獻。
原本s+tagxks+tag_x\le k
現在s+tagx+1ks+tag_x+1\le k或者s+tagx1ks+tag_x-1\le k
實際上只有在s=ktagxs=k-tag_x這個邊界的ff的貢獻會被減去或者加上。挪tagtag的時候順便改一下答案即可。
複雜度O(nn)O(n\sqrt n)

代碼

#include<bits/stdc++.h>
const int Bs = 317, N = 2e5 + 10, P = 998244353;
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int pr[N], las[N], a[N], val[Bs][N], s[N], f[N], tag[Bs], B, Ans, z, k, n;
int belong(int x) {return (x - 1) / B + 1;}
void dec(int &a, int b) {a -= b; if(a < 0) a += P;}
void inc(int &a, int b) {a += b; if(a >= P) a -= P;}
void Ins(int u, int v) {
	int bu = belong(u);
	s[u] -= tag[bu];
	inc(Ans, v); inc(val[bu][s[u] + z], v);
}
void Mdfs(int u, int v) {
	int bu = belong(u);
	if(s[u] + tag[bu] <= k) dec(Ans, f[u - 1]);
	dec(val[bu][s[u] + z], f[u - 1]);
	s[u] += v;
	if(s[u] + tag[bu] <= k) inc(Ans, f[u - 1]);
	inc(val[bu][s[u] + z], f[u - 1]);
}
void Mdf(int L, int R, int v) {
	if(L > R) return ;
	int bl = belong(L), br = belong(R);
	if(bl + 1 >= br) {
		for(int i = L; i <= R; ++i)
			Mdfs(i, v);
	}
	else {
		for(int i = L;i <= bl * B; ++i)
			Mdfs(i, v);
		for(int i = (br - 1) * B + 1; i <= R; ++i)
			Mdfs(i, v);
		for(int i = bl + 1; i < br; ++i) {
			if(~v) dec(Ans, val[i][k - tag[i] + z]);
			else inc(Ans, val[i][k - tag[i] + 1 + z]);
			tag[i] += v;
		}
	}
}
int main() {
	n = ri(); k = ri();
	for(int i = 1, a;i <= n; ++i)
		a = ri(), pr[i] = las[a], las[a] = i;
	B = sqrt(n); z = n;
	f[0] = 1; Ins(1, 1);
	for(int i = 1;i <= n; ++i) {
		Mdf(pr[i] + 1, i, 1);
		Mdf(pr[pr[i]] + 1, pr[i], -1);
		Ins(i + 1, f[i] = Ans);
	}
	printf("%d\n", f[n]);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章