像潮落潮涌,送我奔向自由。|

寂静的海底

园龄:3年2个月粉丝:59关注:15

【题解】CF1613D | dp

(CF1613D)

difficulty:[1800,2200]

类型: 思维,dp,分情况

题意:求一个序列有多少个子序列{ap1,ap2apk}满足

ik,|MEX(ap1api)api|1

要求时间复杂度O(n)

答案模998244353

考虑dp

首先我们考虑第k个元素,只要确定每一步MEX正确,那答案一定MEX正确,因为|MEX(ap1apk)apk|1 所以apk只能为MEX+1,MEX,MEX1,又因为MEX的定义,所以apk只能为MEX±1

接下来考虑定义gi 表示处理到前i位置且最后一位是aiMEX=ai+1的MEX正确序列的个数。

fi表示处理到前i位置且最后一位是aiMEX=ai1的MEX正确序列的个数。

然后你会发现几乎没法转移,因为有一个转移是gigi+1 但是我们不知道i+2位置是否有数,因为你选择的子序列有可能是如下序列

{1,2,,x,x+2,x}

该序列符合定义gi而不能转移到gi+1

所以我们考虑重新定义状态。

dp的状态要定义成该阶段本质上不同(不重不漏)的区分的情况。

思考两个状态的”不同点“有哪些。

首先有两种序列的”样子“(排好序后,1~x+2中那些数有,哪些数没有

第一种:连续的

第二种:跳过一个MEX的。

再考虑目前考虑到的最后一个ai的位置。

(其中考虑ai是在子序列中最后一个出现的数,

可以发现ai只有如下三种可能

那么我们就定义

f(i)表示考虑到前i位,以ai结尾,且MEX=ai1的子序列数。(如下)

g(i)表示考虑到前i位,以ai结尾,且MEX=ai+1,序列中目前未出现过ai+2的子序列数。(如下)

h(i)表示考虑到前i位,以ai结尾,且MEX=ai+1,序列中目前已经出现过ai+2的子序列数。(如下)

发现原本的MEX=ai+1的状态能不能向后转移就取决于x+2有没有数,这样这个问题也得到了解决。

然后就可以列出转移

f(x)=i=1x1f(i)[ai=ax]+i=1x1g(i)[ai=ax2]+i=1x1h(i)[ai=ax2]

第一种是在已经有ax2,ax且最后一个是ax2的基础上再放一个ax

第二种是在目前只有ax2,MEX=ax1的情况下放ax

第三种同理,在已经有ax,但上一位是ax2的情况下放ax

g(x)=i=1x1g(i)[ai=ax,ai=ax1]

只能从后面没有ax+2转移而来,一种是从ax1新放一个ax,一种是重复放一个ax.

h(x)=i=1x1h(x)[ai=ax]+i=1x1f(x)[ai=ax2]

同理,从可能的状态转移而来,因为g(x)是连续的,形成这样的序列必须先有一个”空“.

这个dpO(n2)的,发现值域是[0,n)的,然后

使用三个数组分别为,sf(x),sg(x),sh(x) 分别为a[i]=xf(i),a[i]=xg(i),a[i]=xh(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 @   寂静的海底  阅读(6)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起