专栏文章

题解:AT_arc125_d [ARC125D] Unique Subsequence

AT_arc125_d题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mincvfia
此快照首次捕获于
2025/12/02 00:20
3 个月前
此快照最后确认于
2025/12/02 00:20
3 个月前
查看原文

思路

比较 trick 的 DP。
直接设 dpidp_i 表示以 ii 为结尾的方案数,lstilst_i 表示上一个 ii 出现的位置。考虑什么时候会算重。发现和前面最近的一个数有关。我们发现对于 [1,i1][1,i-1] 的子序列,加上 aia_ialstia_{lst_i} 显然是等效的。 于是它们肯定无法算进贡献里面。
所以方程就是:
dpi=j=lstii1dpjdp_i=\sum_{j=lst_i}^{i-1} dp_j
初值就是第一次出现的时候设为:
1+j=1j1dpj1+\sum_{j=1}^{j-1} dp_j
答案显然是所有 dp 值的和。注意你不应该重复算相同值的 dp 值。

代码

一个坑点是树状数组的写法,注意下标是 00
CPP
#include<bits/stdc++.h>
#define int long long 
using namespace std;
int n,mod=998244353,tr[200010],a[200010],dp[200010],lst[200010];
int lowbit(int x){
	return x&(-x);
} 
void change(int x,int d){
	x++;
	for(int i=x;i<=1+n;i+=lowbit(i)){
		tr[i]=(tr[i]+d)%mod;
	}
}
int query(int x){
	x++;
	int tot=0;
	for(int i=x;i;i-=lowbit(i)) tot=(tot+tr[i])%mod;
	return tot;
}
signed main(){
	#define bnu cin
	#define hzy cout
	#define nkoj .tie(0)
	bnu nkoj;
	hzy nkoj;
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(lst[a[i]]==0) dp[i]=(1+query(i-1))%mod;
		else dp[i]=(query(i-1)-query(max(lst[a[i]]-1,0ll))+mod)%mod;
		change(i,dp[i]);
		change(lst[a[i]],-dp[lst[a[i]]]);
		dp[lst[a[i]]]=0;
		lst[a[i]]=i;
	} 
	cout<<(query(n)+mod)%mod;
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...