2024.10.4

First Post:

Last Update:

Word Count:
727

Read Time:
3 min

模拟赛

数据范围:

感觉自己的思路非常自然,所以写一下。

一开始读错题了,没弄懂它的 是啥意思,以为只要元素一样就行了不用管顺序。

如果不管顺序,那答案就是 。

但是我们是需要考虑顺序的。

那么我们考虑什么时候是不合法的。

例如 3773,这种情况下是不能把这两个数都选进去的,因为一定无法满足顺序一样。

如果我们把每个数看成一条线段,那么可以发现,这种不合法的情况就是两条线段是包含关系。

然后考虑合法情况。

例如样例里的 1122,可以发现怎么选都是合法的。

不难发现,这种情况是两条线段无交。

再例如 1212,可以发现只有两种情况是合法的,要么都选左端点要么都选右端点。

不难发现,这种情况是两条线段有交且不包含。

但如果是一堆线段怎么办?

如果连续若干条线段有交,可以发现总贡献依旧为 2。

如果连续若干条线段无交,可以发现总贡献为 。

那么考虑 dp。

设 表示第 条线段的贡献,转移为

初始值为 ,因为每条线段都有两种选择。

复杂度是 的。考虑优化。

不难发现,我们可以用前缀和来转移。

但这样会少算一部分和多算一部分。

我们把 dp 值放到每条线段的右端点上,然后用树状数组直接查询就可以了。

复杂度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include"bits/stdc++.h"
#define re register
#define int long long
#define lb(x) (x&(-x))
using namespace std;
const int maxn=3e5+10,mod=998244353,inf=6e5;
int n,ans;
int f[maxn],s[maxn],tr[maxn<<1];
struct line{
int l,r;
inline bool operator < (const line &a)const{
return l<a.l;
}
}t[maxn];
inline void add(int x,int val){while(x<=inf) tr[x]=(tr[x]+val)%mod,x+=lb(x);}
inline int query(int x){int res=0;while(x) res=(res+tr[x])%mod,x-=lb(x);return res;}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("std.out","w",stdout);
#endif
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(re int i=1,x;i<=2*n;++i){
cin>>x;
if(!t[x].l) t[x].l=i;
else t[x].r=i;
}
sort(t+1,t+n+1);
for(re int i=1;i<=n;++i){
f[i]=2;
f[i]=(f[i]+s[i-1])%mod;
f[i]=(f[i]+query(t[i].l))%mod;
f[i]=((f[i]-(query(inf)-query(t[i].r))%mod)%mod+mod)%mod;
add(t[i].r,f[i]);
s[i]=(s[i-1]+f[i])%mod;
}
for(re int i=1;i<=n;++i) ans=(ans+f[i])%mod;
cout<<ans;
return 0;
}