[luogu] P1370 Charlie的云笔记序列 线性dp+离散化

前言

传送门 :

题意

给定 n , a [ ] n,a[] n,a[],对于 a [ l , r ] = { a l . . . . a r } a[l,r]=\{a_l....a_r\} a[l,r]={al....ar}

定义 F l , r = a [ l , r ] 中 不 同 子 序 列 的 数 量 F_{l,r}=a[l,r]中不同子序列的数量 Fl,r=a[l,r]

特别的 空串也算一种 (子序列不一定要连续

∑ l = 1 n ∑ r = 1 n F [ l , r ] \sum_{l=1}^{n}\sum_{r=1}^{n}F[l,r] l=1nr=1nF[l,r]

思路

这种题我们考虑 d p dp dp

状态表示 :
f [ i ] f[i] f[i] 表示 ∑ j = 1 i F i j \sum_{j=1}^iF_{ij} j=1iFij

状态计算 :
f [ i ] = f [ i − 1 ] + f [ i − 1 ] + 2 f[i]=f[i-1]+f[i-1]+2 f[i]=f[i1]+f[i1]+2

因为我们加入了 a [ i ] a[i] a[i],因此 f [ i ] f[i] f[i]又多了 f [ i ] f[i] f[i]种,同时 a [ i ] , { } a[i],\{\} a[i],{}也需要记录到答案中

又因为不能出现相同的子序列,因此我们需要考虑判重

对于 k < i k<i k<i, k k k表示最大的 a [ k ] = a [ i ] a[k] = a[i] a[k]=a[i],显然接了 a [ k ] a[k] a[k]的部分都算重复了

并且重复了 f [ k − 1 ] + 1 f[k-1]+1 f[k1]+1 ( k k k前面的以及本身)

因此状态计算还需要变形 :

f [ i ] = f [ i − 1 ] ∗ 2 + 2 − f [ p r e [ a [ i ] ] ] − 1 f[i]=f[i-1]*2+2-f[pre[a[i]]]-1 f[i]=f[i1]2+2f[pre[a[i]]]1

p r e pre pre表示前一个 a [ i ] a[i] a[i]出现的位置,因此我们需要在记录之前先离散化一下

code

const int N = 1e5+10, mod=998244353;
int n,a[N];
int b[N];
int pre[N];
ll dp[N];

void solve(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		b[i] = a[i];
	}
	
	sort(b+1,b+1+n);
	for(int i=1;i<=n;i++){
		a[i] = lower_bound(b+1,b+1+n,a[i])-b;
	}

	
	for(int  i=1;i<=n;i++){
		int t = 0;
		if(pre[a[i]]>0) t = dp[pre[a[i]]-1] +1;
		
		dp[i] = ((dp[i-1]*2+2-t)%mod+mod)%mod;
		
		pre[a[i]] = i ;
		
	}
	
	ll ans =0 ;
	for(int i=1;i<=n;i++){
		ans = (ans+dp[i])%mod;
	}
	cout<<ans<<endl;
	
	
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值