codeforces1129D. Isolation
分析
題目大意:給你一個序列,上面每個位置有一種顏色,求把這個序列分割成若干段,使得每一段的只出現一次的顏色個數不超過個,求方案數。
一個顯然的
重點在於,難以計算。
考慮如何形式化這個問題。
定義數組,如果中顏色第一次出現,那麼,第二次出現,否則
那麼
這個時候考慮的過程。
我們發現,有一個從,有一個從
考慮相對於的變化。
其餘不變。
我們現在要做的事情就是,把當前的所有加起來。
考慮分塊。對於每一塊,記錄每個表示的所有之和。
那麼每一塊,做區間修改是考慮打標記。
也就是說,實際上表示的是的所有之和。
考慮變化的時候對答案的貢獻。
原本
現在或者
實際上只有在這個邊界的的貢獻會被減去或者加上。挪的時候順便改一下答案即可。
複雜度
代碼
#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;
}