[Wannafly冬令营2018Day3] 小游戏

link

题意简述

初始有 $n$ 个小球,小球有 $4$ 种颜色,初始的等级为 $0$

你每一次可以选择一个小球删除,删除后后面的小球会向前 移动一位 

如果有至少 $3$ 个相同颜色和等级的小球连续,那么左侧的 $3$ 个会合并成一个颜色相同等级 $+1$ 的小球(可能有连锁反应)

问有多少种能到达的局面 两个局面是不同当且仅当长度不同或存在一个位置小球不同

$n\leq 10^6$ 。

题目解析

去考虑如何判断一种情况是否存在,比如是否在 $AABABBAB$ 中存在 $A(1)B(1)$ ,可以简单贪心找最近符合要求的球。

设 $f_{i,j,k}$ 表示在 $1-i$ 中最后一个球等级为 $j$ 且有连续 $k$ 个,每次通过倍增处理出下次最近符合条件的位置。

但是 $AABAA$ 在上述算法中看成 $A(1)A(0)$,$A(0)A(1)$ ,但是 $A(1)A(0)$ 却并不能构成,因为是有 $>3$ 个同色球相同的时候是向左合并的 。

而形成这种条件的是 $s_i=s_{i+1}$,考虑这种情况在 $i$ 转移时会发生的情况,若前面产生 $A(x)$ ,则后面产生 $B,C,D$ 不会形成,而只有产生 $A(y)$ 且 $(x<y)$ 时会有一定影响、

如果 $i+1$ 要被使用的话必须 $x<y$ ,而 $i+1$ 不被使用的话可以产生 $A(x)A(y),x<y$ ,因为可以通过 $i+2$ 的不同颜色区分。

时间复杂度 $O(n\log^2n)$,可以通过简单优化实现 $O(n\log n)$ 。

貌似就是个本质不同子序列计数。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define int long long
#define mod 998244353
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return ans*f;
}
const int MAXN=1000011;
int f[MAXN][13][2],len;char str[MAXN];
int now[4],nex[MAXN][4][13],Ans;
signed main(){
//    freopen("1.in","r",stdin);
    len=read();scanf("%s",str+1);
    for(int i=0;i<=12;i++) for(int j=0;j<=3;j++) nex[len+1][j][i]=len+1;
    for(int j=0;j<=3;j++) now[j]=len+1;
    for(int i=len;i>=0;i--){
        for(int j=0;j<=3;j++) nex[i][j][0]=now[j];
        now[str[i]-'A']=i;
    }
    for(int i=1;i<=12;i++) for(int j=0;j<=len;j++) for(int k=0;k<=3;k++) nex[j][k][i]=nex[nex[nex[j][k][i-1]][k][i-1]][k][i-1];
    for(int i=0;i<=len;i++){
        if(i!=len&&str[i]==str[i+1]){
            for(int j=0;j<=12;j++){
                int p=nex[i+1][str[i]-'A'][j];
                for(int k=0;k<j;k++) f[p][j][0]+=f[i][k][0]+f[i][k][1],f[p][j][0]%=mod;
            }
        }
        for(int j=0;j<=12;j++){
            for(int k=0;k<4;k++){
                int p=nex[i][k][j];if(p==len+1) continue;
                if(i==0) f[p][j][0]+=1;
                for(int z=0;z<12;z++){
                    if(str[i]-'A'==k&&j==z) f[p][j][1]+=f[i][z][0],f[p][j][1]%=mod;
                    else if(str[i]-'A'==k&&str[i]==str[i+1]&&z<j) continue;
                    else f[p][j][0]+=f[i][z][0]+f[i][z][1],f[p][j][0]%=mod;
                }
            }Ans+=f[i][j][0]+f[i][j][1],Ans%=mod;
        }
    }printf("%lld\n",Ans);return 0;
}/*
3
ABA
*/
View Code

猜你喜欢

转载自www.cnblogs.com/si-rui-yang/p/12316580.html