ARC125 D - Unique Subsequence(简单dp+树状数组)
目录
Description
从一个长度为 \(n\) 的序列中,找到只出现一次的子序列,输出总个数
State
\(1<=n<=2*10^{5}\)
\(1<=a[i]<=n\)
Input
12
1 2 3 6 9 2 3 3 9 6 1 6
Output
1178
Solution
题目偏向找规律,并不要很强的思维,根据套路,计算每一个数所带来的贡献
来看一组样例 :\(1\ 4\ 3\ 3\ 3\ 2\),令 \(dp[i]\) 表示 \(i\) 位置所产生的贡献,其答案依次为 \(1\ 2\ 4\ 4\ 4\ 6\),每次计算答案,如果原来出现 \(x\),先将其位置上的答案清空,然后当前位置的答案就是 前缀和 + 1
但是样例这样是过不了的,再看一组样例 \(1\ 2\ 3\ 2\ 3\),按上述思路,最后的答案为 \(15\),但结果应该是 \(17\),其实上面的分析并不完全正确,如果原来出现 \(x\), 那么当前位置 \(now\) 的答案为 \(\sum_{i=pos[x]}^{now-1}dp[i]\)
Code
const int N = 2e5 + 5;
ll n, m, _;
int i, j, k;
ll a[N];
ll c[N];
int vis[N];
ll adp(ll &x)
{
x %= mod;
x += mod;
x %= mod;
return x;
}
void add(int x, ll delta)
{
adp(delta);
while(x < N){
c[x] += delta;
adp(c[x]);
x += lowbit(x);
}
return void();
}
ll ask(int x)
{
ll ans = 0;
while(x){
ans += c[x];
adp(ans);
x -= lowbit(x);
}
return ans;
}
signed main()
{
//IOS;
while(~ sd(n)){
fill(vis, 0);
fill(c, 0ll);
rep(i, 1, n){
sd(a[i]);
}
rep(i, 1, n){
if(vis[a[i]]){
ll res = ask(vis[a[i]]) - ask(vis[a[i]] - 1);
add(i, ask(i - 1) - ask(vis[a[i]] - 1));
add(vis[a[i]], -res);
}
else{
add(i, ask(i - 1) + 1);
}
vis[a[i]] = i;
}
pll(ask(n));
}
//PAUSE;
return 0;
}