【题解】CF1613D | dp

(CF1613D)

$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;
}
posted @ 2021-12-30 19:02  寂静的海底  阅读(4)  评论(0编辑  收藏  举报  来源