【ARC125D】Unique Subsequence

题目

题目链接:https://atcoder.jp/contests/arc125/tasks/arc125_d
给定一个长度为 \(n\) 的序列 \(a\)。求有多少个 \(a\) 的子序列 \(b\),满足在 \(a\) 的子序列可重集中,\(b\) 恰好出现了一次。
\(n\leq 2\times 10^5\)

思路

假设一个长度为 \(m\) 的子序列 \(b\)\(a\) 的一个前缀 \(a[1\sim n']\) 中恰好出现了一次(\(n'\) 就是 \(b_m\) 的下标),考虑在这个子序列后面加入下标为 \(i\) 的元素 \(a_i\)\(i>n'\))。
手玩一下发现,只需要满足在 \((n',i)\) 这个区间中,不存在数字 \(b_m\)\(a_i\) 即可。
\(f[i]\) 表示 \(a\) 中前 \(i\) 个元素有多少个子序列只出现了一次(且 \(i\) 强制选上),那么如果 \(f[i]\) 可以转移到 \(f[j]\),当且仅当 \((i,j)\) 中没有 \(a_i\)\(a_j\)
维护一个树状数组,当我们求完 \(f_i\) 后,把 \(f_i\) 插入树桩数组,当到达下一个为 \(a_i\) 的位置时,把 \(f[i]\) 从树状数组中删除。然后对于 \(j\)\(f[j]\) 只需要在树状数组中求一下区间 \([pre[j],j]\) 的和即可。
时间复杂度 \(O(n\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=200010,MOD=998244353;
int n,a[N],nxt[N],pre[N],last[N];
ll ans,f[N];

struct BIT
{
	ll c[N];
	
	void add(int x,ll v)
	{
		for (int i=x;i<=n+1;i+=i&-i)
			c[i]=(c[i]+v)%MOD;
	}
	
	ll query(int x)
	{
		ll ans=0;
		for (int i=x;i;i-=i&-i)
			ans=(ans+c[i])%MOD;
		return ans;
	}
}bit;

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		if (last[a[i]])
			nxt[last[a[i]]]=i,pre[i]=last[a[i]];
		last[a[i]]=i;
	}
	bit.add(1,1);
	for (int i=1;i<=n;i++)
	{
		f[i]=(bit.query(i)-bit.query(pre[i]))%MOD;
		if (pre[i]) bit.add(pre[i]+1,-f[pre[i]]);
		if (!nxt[i]) ans=(ans+f[i])%MOD;
		bit.add(i+1,f[i]);
	}
	cout<<(ans%MOD+MOD)%MOD;
	return 0;
}
posted @ 2021-08-23 09:29  stoorz  阅读(250)  评论(0编辑  收藏  举报