【题解】CF1613D | dp
$difficulty: [1800 , 2200] $
类型: 思维,dp,分情况
题意:求一个序列有多少个子序列$\{a_{p_1},a_{p_2} \dots a_{p_k}\}$满足
$$ \forall i\leq k ,\left| MEX(a _{p_1}\dots a_{p_i}) -a_{p_i} \right| \leq1 $$
要求时间复杂度$O(n)$
答案模998244353
考虑dp
首先我们考虑第k个元素,只要确定每一步MEX正确,那答案一定MEX正确,因为$ \left| MEX(a _{p_1}\dots a_{p_k}) -a_{p_k} \right| \leq1$ 所以$a_{p_k}$只能为$MEX+1,MEX,MEX-1$,又因为$MEX$的定义,所以$a_{p_k}$只能为$MEX\pm 1$
接下来考虑定义$g_i$ 表示处理到前$i$位置且最后一位是$a_i$且$MEX=a_i+1$的MEX正确序列的个数。
$f_i$表示处理到前$i$位置且最后一位是$a_i$且$MEX=a_i-1$的MEX正确序列的个数。
然后你会发现几乎没法转移,因为有一个转移是$g_i \to g_{i+1}$ 但是我们不知道$i+2$位置是否有数,因为你选择的子序列有可能是如下序列
$$ \{ 1,2,\dots ,x,x+2,x \} $$
该序列符合定义$g_i$而不能转移到$g_{i+1}$
所以我们考虑重新定义状态。
dp的状态要定义成该阶段本质上不同(不重不漏)的区分的情况。
思考两个状态的”不同点“有哪些。
首先有两种序列的”样子“(排好序后,1~x+2中那些数有,哪些数没有
第一种:连续的
第二种:跳过一个MEX的。
再考虑目前考虑到的最后一个$a_i$的位置。
(其中考虑$a_i$是在子序列中最后一个出现的数,
可以发现$a_i$只有如下三种可能
那么我们就定义
$f(i)$表示考虑到前$i$位,以$a_i$结尾,且$MEX=a_i-1$的子序列数。(如下)
$g(i)$表示考虑到前$i$位,以$a_i$结尾,且$MEX=a_i+1$,序列中目前未出现过$a_i+2$的子序列数。(如下)
$h(i)$表示考虑到前$i$位,以$a_i$结尾,且$MEX=a_i+1$,序列中目前已经出现过$a_i+2$的子序列数。(如下)
发现原本的$MEX=a_i+1$的状态能不能向后转移就取决于$x+2$有没有数,这样这个问题也得到了解决。
然后就可以列出转移
$f(x) = \sum_{i=1}^{x-1} f(i)[a_i=a_x] + \sum_{i=1}^{x-1} g(i) [a_i=a_x-2] +\sum_{i=1}^{x-1} h(i)[a_i=a_x-2]$
第一种是在已经有$a_x-2,a_x$且最后一个是$a_x-2$的基础上再放一个$a_x$
第二种是在目前只有$a_x-2$,$MEX=a_x-1$的情况下放$a_x$
第三种同理,在已经有$a_x$,但上一位是$a_x-2$的情况下放$a_x$
$g(x) = \sum_{i=1}^{x-1} g(i)[a_i=a_x,a_i=a_x-1]$
只能从后面没有$a_x+2$转移而来,一种是从$a_x-1$新放一个$a_x$,一种是重复放一个$a_x$.
$h(x) =\sum_{i=1}^{x-1} h(x) [a_i=a_x]+ \sum_{i=1}^{x-1} f(x)[a_i=a_x-2]$
同理,从可能的状态转移而来,因为$g(x)$是连续的,形成这样的序列必须先有一个”空“.
这个$dp$是$O(n^2)$的,发现值域是$[0,n)$的,然后
使用三个数组分别为,$sf(x),sg(x),sh(x)$ 分别为$a[i]= x $的$\sum f(i)$,$a[i]= x $的$\sum g(i)$,$a[i]= x $的$\sum h(i)$
然后转移即可。
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,谢谢你的阅读或转载!