【题解】ARC215 D - Unique Subsequence

题意:给你一个序列 a a a 找到只在 a a a 序列中出现一次的子序列数量。

solution:
考虑怎么去重。
首先满足条件的序列一定是包含在 a a a 的子序列中的。
设 dp[i] 表示必选第 i 个字符,满足条件的不同子序列数量。
先说转移方程: d p [ i ] = ∑ d p [ j ] dp[i]=\sum dp[j] dp[i]=dp[j] , 其中 j 满足 : 对于任意 k ∈ [ i + 1 , j − 1 ] k\in [i+1,j-1] k[i+1,j1] a [ k ] ≠ a [ i / j ] a[k]\ne a[i/j] a[k]=a[i/j]
解释一下,首先如果满足 a[k]=a[i/j] ,那么可以将 i/j 其中之一替换成 k 得到相同的子序列,肯定是不合法的;其次这样的序列一定是唯一存在的,证明:从后往前 select 保证字典序最大,必须 select 直到 0;从前往后 select 保证字典序最小,必须 select 直到 n+1 ,保证字典序最小,两种得到的序列是唯一个。
最后答案是 ∑ d p [ l s t [ i ] ] \sum dp[lst[i]] dp[lst[i]] 。用线段树维护即可。
代码极短,思维极难。

#include<bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
#define PII pair<int,int>
using namespace std;
const int mx=2e5+5;
const int mod=998244353;
int n,dp[mx],lst[mx],t[mx<<2];
void PushUp(int p) {t[p]=(t[p<<1]+t[p<<1|1])%mod;} 
void add(int &x,int y) {x+=y; if(x>mod) x-=mod;}
void upd(int p,int l,int r,int x,int y) {
	if(l==r) {t[p]=y;return;}
	int mid=l+r>>1; x<=mid?upd(p<<1,l,mid,x,y):upd(p<<1|1,mid+1,r,x,y);
	PushUp(p);
}
int qry(int p,int l,int r,int ql,int qr) {
	if(ql<=l&&r<=qr) return t[p];
	int mid=l+r>>1,res=0; if(ql<=mid) add(res,qry(p<<1,l,mid,ql,qr));
	if(mid<qr) add(res,qry(p<<1|1,mid+1,r,ql,qr));
	return res;  
}
signed main() { 
    cin>>n; upd(1,1,n+1,1,1); 
    for(int i=2;i<=n+1;i++) {
    	ll x; cin>>x;
    	dp[i]=qry(1,1,n+1,lst[x],i);
    	if(lst[x]) upd(1,1,n+1,lst[x],0);
    	lst[x]=i; upd(1,1,n+1,i,dp[i]);
	}
	int res(0);
	for(int i=1;i<=n;i++) {
		if(lst[i]) add(res,dp[lst[i]]);
	}
	printf("%d",res);
}
posted @ 2021-08-23 11:47  仰望星空的蚂蚁  阅读(6)  评论(0)    收藏  举报  来源