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;
}
posted @ 2021-09-11 09:05  Bcoi  阅读(140)  评论(0)    收藏  举报