バイトの競プロメモ

主に競技プログラミング

AtCoder Regular Contest 125 D - Unique Subsequence

D - Unique Subsequence

f:id:baitop:20210920185630p:plain

考えたこと

 

dp[i] := iを先頭に使ったときの答えとして

iを後ろから更新する時にどう遷移するかを考える

 

以降A[i]の後ろにA[j]から始まる部分列を付け加えられる事を

iにjを加えられると呼ぶことにする

f:id:baitop:20210920190255p:plain


上の図を見るとA[i]==A[j]かつi<jを満たす最小のjについて

iにk(j+1<=k<=N)を加えることは出来ないことが分かる。

なぜなら、jにkを加えることで同じ部分列が作れてしまうためである。

反対に、iにk(i+1<=k<=j)を加えることは出来る

 

よってiを後ろから見ていき

dp[i] = sigma(k=i+1~j,  dp[k])

dp[j] = 0

とすればいい、ちなみにdp[j]を0にする理由は上に書いたようにjを先頭にした時の部分列はiを先頭にして同じものが作れてしまうため、問題文の条件に反するから。

この操作はbinary indexed treeやセグメントツリーで出来る

 

void solve() {
int N;
vi A(N);
cin >> N;
for (auto &a : A)cin >> a;
seg<modint> dp(N + 1);
vi pos(N + 1, N);
rer(i, N - 1) {
int j = pos[A[i]];
modint sum = dp(i + 1, j + 1);
if (j == N)sum++;//自分だけ使う
dp.update(i, sum);

pos[A[i]] = i;
dp.update(j, 0);
}
cout<dp(0, N+1)<<endl;
}