• 2023NOIP A层联测10-子序列


    题目

    预处理出 p r e i , j , n x t i , j pre_{i,j},nxt_{i,j} prei,j,nxti,j 分别表示第 i i i 个字符前/后第一个字符 j j j 的出现位置。

    对于每个字符 S i S_i Si,考虑在只保留它时序列被分成了若干段(?????i?i??i????i?? ),预处理出 s u m i , j sum_{i,j} sumi,j 表示以 j j j 字符为分隔点,将序列分成若干段, S i S_i Si 所在的段及其之后的段含有 S i S_i Si 的个数减一。不懂?放个图就懂了。

    在这里插入图片描述 可以递推求出 s u m i , j sum_{i,j} sumi,j

    s u m i , j = s u m n x t i , S i + [ n x t i , S i > n x t i , j ] sum_{i,j}=sum_{nxt_{i,S_i}}+[nxt_{i,S_i}>nxt_{i,j}] sumi,j=sumnxti,Si+[nxti,Si>nxti,j]

    意思就是如果 j j j 夹在 S i S_i Si 中间,就可以从后面转移过来。

    对于每一次询问,枚举答案的两个字符 c 1 , c 2 c_1,c_2 c1,c2,找出区间内第一次和最后一次 c 1 c_1 c1 出现的位置 L , R L,R L,R 2 ( s u m L , c 1 − s u m R , c 1 ) + 1 + [ p r e r + 1 , c 2 > R ] 2(sum_{L,c_1}-sum_{R,c_1})+1+[pre_{r+1,c_2}>R] 2(sumL,c1sumR,c1)+1+[prer+1,c2>R] 就是最长的好子序列长度。这样就求出了答案。

    具体实现看代码

    #include
    using namespace std;
    const int N=1.5e6+2;
    char a[N];
    int m,pre[N][26],nxt[N][26],sum[N][26];
    int main()
    {
        freopen("seq.in","r",stdin);
        freopen("seq.out","w",stdout);
        scanf("%s",a+1);
        int n=strlen(a+1);
        for(int i=1;i<=n+1;i++){
            for(int j=0;j<26;j++){
                if(a[i-1]==j+97) pre[i][j]=i-1;
                else pre[i][j]=pre[i-1][j];
            }
        }
        for(int i=0;i<26;i++) nxt[n+1][i]=n+1;
        for(int i=n;i>=0;i--){
            for(int j=0;j<26;j++){
                if(a[i+1]==j+97) nxt[i][j]=i+1;
                else nxt[i][j]=nxt[i+1][j];
            }
            for(int j=0;j<26;j++){
                sum[i][j]=sum[nxt[i][a[i]-97]][j]+(nxt[i][a[i]-97]>nxt[i][j]);
            }
        }
        scanf("%d",&m);
        for(int i=1,l,r;i<=m;i++){
            scanf("%d%d",&l,&r);
            int maxn=-1;
            char c1=0,c2=0;
            for(int i=0;i<26;i++){
                for(int j=0;j<26;j++){
                    if(i==j) continue;
                    if(nxt[l-1][i]>r) continue;
                    int L=nxt[l-1][i],R=pre[r+1][i];
                    int ans=(sum[L][j]-sum[R][j])*2+1+(pre[r+1][j]>R);
                    if(ans>maxn) maxn=ans,c1=i+97,c2=j+97;
                }
            }
            printf("%d %c%c\n",maxn,c1,c2);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
  • 相关阅读:
    黑磷和量子点结合分子印迹技术的荧光传感材料(BPS-QDs@MIP)
    [JavaWeb] Tomcat 基础安装和使用
    RabbitMQ怎么保证可靠性
    解决前端二进制流下载的文件(例如:excel)打不开的问题
    Java学习day01
    【Flutter】Flutter C/C++ 插件的开发 (支持 windows、macos、ios、android )
    10万奖金被瓜分,快来认识这位上榜者里的“乘风破浪的姐姐”
    不就是Java吗之数组的定义和使用
    MOOC 大数据Note
    vim,emacs,verilog-mode这几个到底是啥关系?
  • 原文地址:https://blog.csdn.net/dygxczn/article/details/133797835