[ARC125D] Unique Subsequence

前言

有网赛 DEBUFF 加身的我果然不一样,直接梦中想题。

题目

AtCoder

题目大意:

给一个长度为 \(N\) 的序列 \(A\)\(s\)\(A\) 的非空子序列,询问有多少不同的个 \(s\) 可以被 \(A\) 唯一表示,答案对 \(998244353\) 取模。

  • \(1\le N\le 2\times 10^5\)
  • \(1\le A_i\le N\)
  • 所有数都是整数。

注:\(s\)\(A\) 唯一表示的意思是,只存在一个独一无二的序列 \(id\) 使得 \(A_{id(i)}=s_i\).

其实英文题面挺短的,可以看一看。

讲解

为方便表示,我们令 \(A_0=id_0=0,A_{N+1}=id_{N+1}=N+1\).

我们将唯一表示的条件具体化,可以发现对于 \(i\in[0,N]\)\(A_{id(i)+1},A_{id(i)+2},...,A_{id(i+1)-1}\) 不等于 \(A_{id(i)}\)\(A_{id(i+1)}\)

也就是说我们选的子序列中的相邻两个数中间不能有和它们相同的数。

然后我们就可以考虑对以权值 \(i\) 结尾的方案数进行维护。

单点修改,区间查询,用树状数组即可。

代码

一看就懂的代码
//12252024832524
#include <cstdio>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std; 
 
typedef long long LL;
const int MAXN = 200005;
const int MOD = 998244353;
int n,ans;
int lst[MAXN],dp[MAXN];
 
LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
 
int B[MAXN];
int lowbit(int x){return x & -x;}
void Mod(int &x,int val){x += val;if(x >= MOD) x -= MOD;}
void Add(int x,int val){for(;x <= n;x += lowbit(x)) Mod(B[x],val);}
int Sum(int x){int ret = 0;for(;x >= 1;x -= lowbit(x)) Mod(ret,B[x]);return ret;}
 
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read();
	for(int i = n,val;i >= 1;-- i)//倒着来是为了计数方便
	{
		val = Read();
		if(lst[val]) dp[i] = Sum(lst[val]),Add(lst[val],MOD-dp[lst[val]]);
		else dp[i] = Sum(n)+1;
		Add(lst[val] = i,dp[i]);
	}
	for(int i = 1;i <= n;++ i) Mod(ans,dp[lst[i]]);
	Put(ans);
	return 0;
}
posted @ 2021-08-23 15:41  皮皮刘  阅读(86)  评论(0编辑  收藏  举报