ARC125D 题解
ARC125D
题意
给定长度为
题解
不难发现,一个只出现过一次的子序列合法的充分必要条件是:
- 头部元素
是原序列中下标最小的(即最左边的)值为 的元素 - 由对称性,该子序列最后一个元素
是原序列中最后一个出现的值为 的元素 - 子序列中任意相邻两元素在原序列中,不妨设它们的下标分别是
则 , 且
这些条件可以举一些例子验证。
为了简化程序,我们可以为原序列设首尾两个哨兵,
具体地,令
这样
接着,我们求以
我们就不必考虑条件 1 和条件 2 了。
然后就可以 dp 了,
记
实际我们需要不断维护
再加上单点修改,可以直接树状数组维护。
参考代码
#include<bits/stdc++.h> using namespace std; const int N=200010; typedef long long ll; const int mod=998244353; int a[N],n,c[N],f[N],lst[N],m; inline int lowbit(int x){return x&-x;} void add(int x,int val){ x++; //由于要用到0这个下标,树状数组中把所有下标偏移1 for(;x<=n+1;x+=lowbit(x)) c[x]=((c[x]+val)%mod+mod)%mod; } int ask(int x){ x++; //同上 int ret=0; for(;x;x-=lowbit(x)) ret=((ret+c[x])%mod+mod)%mod; return ret; } int main(){ cin>>n; for(int i=1; i<=n; i++){ scanf("%d",&a[i]); m=max(m,a[i]); } a[0]=m+1,a[n+1]=m+2; //设哨兵 f[0]=1; add(0,1); for(int i=1; i<=n+1; i++){ f[i]=(ask(i-1)-ask(lst[a[i]]-1)+mod)%mod; if(lst[a[i]]) add(lst[a[i]],-f[lst[a[i]]]); add(i,f[i]); lst[a[i]]=i; } cout<<(f[n+1]-1+mod)%mod; //子序列不能空,所以减1 return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】