Codeforces Round #531 (Div. 3) E. Monotonic Renumeration(离散化+区间合并)

题意

给你一个序列,要你根据这个序列构造一个新序列,

要求新序列的下一个数只能与上一个数相同或为上一个数+1

且原序列中相同的数,在新序列对应的位置的数也得相同

在新序列第一个数恒为0的情况下,

求有多少种构造序列的方式

思路来源

cf某神仙代码

题解

基础部分:

显然把一个数最开始出现和最后出现的位置理解成一个区间则区间中的数均相同

若区间i与区间j相交,显然i和j的数也均需相同,合并为统一区间

那么就是求除了第一个数所在的区间以外,还有num个独立的区间,

每个区间对应与上一个区间相同或上一个区间+1两种选择,

答案即为modpow(2,num,mod),modpow为快速幂

技巧:

①离散化

将原序列排序,二分找到原序列在对应排序序列中第一次出现的位置,即为原序列的最小rank

把原序列的值赋为rank值,这样1e9就缩到2e5了

简直不能再巧妙好嘛!以前天天说离散化都不会这样离散化真是菜哭了55555

②区间合并

开一个mx[]数组记录a[i]在数组中出现的最后一次下标,增序遍历覆盖一下就ojbk

增序遍历位置i,nowr更新前面已存在的区间的可达最右端点

如果i在nowr左边,说明被以前的区间覆盖了,不用开新区间

否则和之前的区间没有交集,开一个新区间,num++

每次更新nowr=max(nowr,mx[a[i]])

最后求一下2的num次方%mod就好了,快速幂也能写懒得写了

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
const int mod=998244353;
int n,a[maxn],b[maxn],num,mx[maxn];
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;++i)scanf("%d",&a[i]),b[i]=a[i];
	sort(b,b+n);
	for(int i=0;i<n;++i)a[i]=lower_bound(b,b+n,a[i])-b;//用rank来离散化
	for(int i=0;i<n;++i)mx[a[i]]=i;//a[i]出现的最大位置
	int nowr=0;
	ll ans=1;
	for(int i=0;i<n;++i)
	{
	 if(i>nowr)num++;//没到 新开一个区间 注意b1==0恒成立 被b1吞并的都得为0 
	 nowr=max(nowr,mx[a[i]]);//开的多个区间 都能吞并nowr以左的数 
	}
	for(int i=0;i<num;++i) 
	{
		ans*=2;
		if(ans>=mod)ans%=mod;
	}
	printf("%I64d\n",ans);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值