【题解】CF1613D | dp
类型: 思维,dp,分情况
题意:求一个序列有多少个子序列满足
要求时间复杂度
答案模998244353
考虑dp
首先我们考虑第k个元素,只要确定每一步MEX正确,那答案一定MEX正确,因为 所以只能为,又因为的定义,所以只能为
接下来考虑定义 表示处理到前位置且最后一位是且的MEX正确序列的个数。
表示处理到前位置且最后一位是且的MEX正确序列的个数。
然后你会发现几乎没法转移,因为有一个转移是 但是我们不知道位置是否有数,因为你选择的子序列有可能是如下序列
该序列符合定义而不能转移到
所以我们考虑重新定义状态。
dp的状态要定义成该阶段本质上不同(不重不漏)的区分的情况。
思考两个状态的”不同点“有哪些。
首先有两种序列的”样子“(排好序后,1~x+2中那些数有,哪些数没有
第一种:连续的
第二种:跳过一个MEX的。
再考虑目前考虑到的最后一个的位置。
(其中考虑是在子序列中最后一个出现的数,
可以发现只有如下三种可能
那么我们就定义
表示考虑到前位,以结尾,且的子序列数。(如下)
表示考虑到前位,以结尾,且,序列中目前未出现过的子序列数。(如下)
表示考虑到前位,以结尾,且,序列中目前已经出现过的子序列数。(如下)
发现原本的的状态能不能向后转移就取决于有没有数,这样这个问题也得到了解决。
然后就可以列出转移
第一种是在已经有且最后一个是的基础上再放一个
第二种是在目前只有,的情况下放
第三种同理,在已经有,但上一位是的情况下放
只能从后面没有转移而来,一种是从新放一个,一种是重复放一个.
同理,从可能的状态转移而来,因为是连续的,形成这样的序列必须先有一个”空“.
这个是的,发现值域是的,然后
使用三个数组分别为, 分别为的,的,的
然后转移即可。
code:(又臭又长)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lll __int128
#define lb long double
#define pb push_back
#define mp make_pair
#define min3(xxx,yyy,zzz) min(min(xxx,yyy),zzz)
#define max3(xxx,yyy,zzz) max(max(xxx,yyy),zzz)
#define pii pair<int,int>
#define pll pair<ll,ll>
#define fi first
#define se second
#define rep(variable,leftrange,rightrange) for(int variable=leftrange;variable<=rightrange;++variable)
#define Rep(variable,leftrange,rightrange) for(int variable=leftrange;variable>=rightrange;--variable)
#define mem(x,y) memset(x,y,sizeof x)
#define sq(x) ((x)*(x))
#define ss stable_sort
#define rs random_shuffle
#define nxp next_permutation
#define lowbit(x) (x& -x)
#define gi greater<int>
#define gl greater<ll>
#define vl vector<ll>
#define vi vector<int>
#define upmin(x,y) x=min(x,y)
#define upmax(x,y) x=max(x,y)
#define Finda(a,siz,b) (lower_bound(a+1,a+siz+1,b)-a)
#define Findv(a,b) (lower_bound(a.begin(),a.end(),b)-a.begin())
template <typename T>inline void read(T &t)
{ll c=getchar();t=0;while(!isdigit(c))c=getchar();while(isdigit(c))t=(t<<3)+(t<<1)+c-48,c=getchar();}
template <typename T,typename... Args> inline void read(T& t, Args&... args){read(t);read(args...);}
template <typename T> inline void wrt(T x)
{if(0<=x&&x<10) {putchar(x+'0');return ;}wrt(x/10);putchar(x%10+'0');}
template <typename T> inline void wrt(T x,char c) {wrt(x);putchar(c);}
//__code-space :Mint
#define Add(x,y) x=(x+y)%mod
#define Sub(x,y) x=(x+mod-y%mod))%mod
#define Tim(x,y) x=(x%mod*y%mod)%mod
#define Div(x,y) x=(x%mod*ny(y)%mod)%mod
const int mod =998244353;
const int N= 5e5+200 ;
int n,a[N];
ll dp[N][3],sum[N][3];
#define f(x) dp[x][0]
#define g(x) dp[x][1]
#define h(x) dp[x][2]
#define sf(x) sum[x][0]
#define sg(x) sum[x][1]
#define sh(x) sum[x][2]
//f(x) -> Mex = x-1 **********_x
//g(x) -> Mex = x+1 There's no x+2 ***********x_
//h(x) -> Mex = x+1 There's x+2 ***********x_*
//h(x)->f(x+2)
//g(x)->f(x+2)
//f(x)->f(x)
//f(x)->h(x)
//g(x)->h(x)
ll ans ;
void work()
{
ans = 0;
read(n);
rep(i,1,n)
read(a[i]);
rep(i,0,n)
rep(j,0,2)
dp[i][j]=sum[i][j]=0;
rep(i,1,n)
{
f(i)=(a[i]==1)?1:0;
g(i)=(a[i]==0)?1:0;
h(i)=0;
/*---------update f(x) ---------------*/
Add(f(i) , sf(a[i]));
if(a[i]>=2)
Add(f(i) , sg(a[i]-2)),
Add(f(i) , sh(a[i]-2));
/*-------------g(x) ----------------*/
if(a[i]>=1)
Add(g(i) , sg(a[i]-1));
Add(g(i) , sg(a[i])) ;
/*-------------h(x) --------------*/
Add(h(i) , sh(a[i]) );
if(a[i]+2<=n)
Add(h(i) , sf(a[i]+2) );
/*-------------update the sum-------------*/
Add(sf(a[i]) , f(i) );
Add(sh(a[i]) , h(i) );
Add(sg(a[i]) , g(i) );
/*------------- upd the ans------------*/
Add(ans,f(i));
Add(ans,g(i));
Add(ans,h(i));
}
wrt(ans,'\n');
return ;
}
int T;
int main()
{
read(T);
while(T--) work() ;
return 0;
}
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17970987,谢谢你的阅读或转载!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步