2023.11.10联赛 T4题解

题目大意

题目思路

我们考虑分块处理。

我们可以维护一个状态,表示块内每个字母对应的真实字母,因为只有 3 3 3个字母,所以只有 6 6 6种情况。

对于每一个块,我们可以对于每种状态、每种块,预处理出以 A A A或 B B B或 C C C进入出来时是什么字母。

至此,思路就很明了。

修改操作对于散块直接修改,对于整块修改他们的状态。

查询操作对于散块直接跳,对于整块直接用预处理的信息跳即可。

具体实现参考代码。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,q,a[N],b[N],pos[N],posl[N],posr[N],g[N],sum[N][10][5],p[10][5],vis[5][5][5],block=0,tot=0;
char s[N],s1[200+10],s2[200+10];
int read()
{
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
        s=s*10+(ch-'0'),ch=getchar();
    return s*w;
}
int work(int l,int r,int state,int x)
{
    for(int i=l;i<=r;++i)
    {
        int val=p[state][a[i]];
        if(x%3+1!=val)
            x=val;
    }
    return x;
}
void change(int l,int r,int val1,int val2)
{
    int x=0,y=0;
    for(int i=1;i<=3;++i)
        if(p[g[pos[l]]][i]==val1)
            x=i;    
    for(int i=1;i<=3;++i)
        if(p[g[pos[l]]][i]==val2)
            y=i; 
    for(int i=l;i<=r;++i)
    {
        if(p[g[pos[l]]][a[i]]==val1)
            a[i]=y;
        else if(p[g[pos[l]]][a[i]]==val2)
            a[i]=x;
    }
    for(int i=1;i<=6;++i)   
        for(int j=1;j<=3;++j)
            sum[pos[l]][i][j]=work(posl[pos[l]],posr[pos[r]],i,j);
}   
void update(int l,int r,int val1,int val2)
{
    if(pos[l]==pos[r])
    {
        change(l,r,val1,val2);
        return ;
    }
    change(l,posr[pos[l]],val1,val2);
    for(int i=pos[l]+1;i<=pos[r]-1;++i)
    {
        int c[5];
        for(int j=1;j<=3;++j)
        {
            if(p[g[i]][j]==val1)
                c[j]=val2;
            else if(p[g[i]][j]==val2)
                c[j]=val1;
            else
                c[j]=p[g[i]][j];
        }
        g[i]=vis[c[1]][c[2]][c[3]];
    }
    change(posl[pos[r]],r,val1,val2);
}
int ask(int l,int r,int x)
{
    if(pos[l]==pos[r])
        return work(l,r,g[pos[l]],x);
    x=work(l,posr[pos[l]],g[pos[l]],x);
    for(int i=pos[l]+1;i<=pos[r]-1;++i)
        x=sum[i][g[i]][x];
    x=work(posl[pos[r]],r,g[pos[r]],x);
    return x;
}
int main()
{
    freopen("training.in","r",stdin);
    freopen("training.out","w",stdout);
    n=read(),q=read();
    scanf("%s",s+1);
    block=pow(n,2.0/5.0);
    for(int i=1;i<=n;++i)
        a[i]=s[i]-'A'+1,pos[i]=(i-1)/block+1;
    for(int i=1;i<=pos[n];++i)
    {
        posl[i]=(i-1)*block+1;
        posr[i]=min(i*block,n);
        g[i]=1;
    }
    for(int i=1;i<=3;++i)
        b[i]=i;
    do
    {
        tot++;
        p[tot][1]=b[1];
        p[tot][2]=b[2];
        p[tot][3]=b[3];
        vis[b[1]][b[2]][b[3]]=tot;
        for(int i=1;i<=3;++i)
            for(int j=1;j<=pos[n];++j)
                sum[j][tot][i]=work(posl[j],posr[j],tot,i);
    }while(next_permutation(b+1,b+4));
    while(q--)
    {
        int opt=read(),l=read(),r=read();
        if(opt==0)
        {
            scanf("%s %s",s1+1,s2+1);
            update(l,r,s1[1]-'A'+1,s2[1]-'A'+1);            
        }
        else
        {
            scanf("%s",s1+1);
            printf("%c\n",ask(l,r,s1[1]-'A'+1)+'A'-1);
        }
    }
    return 0;
}
相关推荐
passer__jw7671 小时前
【LeetCode】【算法】3. 无重复字符的最长子串
算法·leetcode
passer__jw7671 小时前
【LeetCode】【算法】21. 合并两个有序链表
算法·leetcode·链表
sweetheart7-72 小时前
LeetCode22. 括号生成(2024冬季每日一题 2)
算法·深度优先·力扣·dfs·左右括号匹配
李元豪3 小时前
【智鹿空间】c++实现了一个简单的链表数据结构 MyList,其中包含基本的 Get 和 Modify 操作,
数据结构·c++·链表
我不是星海3 小时前
1.集合体系补充(1)
java·数据结构
景鹤4 小时前
【算法】递归+回溯+剪枝:78.子集
算法·机器学习·剪枝
_OLi_5 小时前
力扣 LeetCode 704. 二分查找(Day1:数组)
算法·leetcode·职场和发展
丶Darling.5 小时前
Day40 | 动态规划 :完全背包应用 组合总和IV(类比爬楼梯)
c++·算法·动态规划·记忆化搜索·回溯
风影小子5 小时前
IO作业5
算法
奶味少女酱~5 小时前
常用的c++特性-->day02
开发语言·c++·算法