zoukankan      html  css  js  c++  java
  • codeforces#1120C. Compress String(dp+后缀自动机)

    题目链接:

    https://codeforces.com/contest/1120/problem/C

    题意:

    从前往后压缩一段字符串

    有两种操作:

    1.对于单个字符,压缩它花费$a$

    2.对于末尾一段字符串,如果这段字符串是已经压缩过字符串的子串,那么可以选择压缩它,花费为$b$

    数据范围:

    $1leq |S| leq 5000$

    $1leq a leq 5000$

    $1leq b leq 5000$

    分析: 

    这道题目我们需要解决一个问题,计算某个子串出现的最早位置

    转移,如果这个字串出现的最早位置不是当前位置,也就是说这个字串在前面还出现了一次,那么可以执行第二种操作

    对于指定状态可以根据子状态转移,取最小的子状态的最早位置

    给出子串下标求出子串出现的最早位置,首先得到子串在sam中的状态,根据状态得到最早出现的位置

    AC代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=5000+10;
    char S[maxn];
    int n,a,b;
    struct suffixautomation
    {
        int mp[maxn*2][30],fa[maxn*2],ed,ct,len[maxn*2],minpos[maxn*2],deg[maxn*2],pos[maxn][maxn];
        int dp[maxn];
        suffixautomation(){ed=ct=1;}
        inline void ins(int c,int pos)
        {
            int p=ed;ed=++ct;minpos[ed]=pos;len[ed]=pos;//先初始化size和len
            for(;p&&mp[p][c]==0;p=fa[p]){mp[p][c]=ed;}//然后顺着parent树的路径向上找
            if(p==0){fa[ed]=1;return;}int q=mp[p][c];//case1
            if(len[p]+1==len[q]){fa[ed]=q;return;}//case2
            len[++ct]=len[p]+1;//case 3
            for(int i=1;i<=26;i++){mp[ct][i]=mp[q][i];}
            fa[ct]=fa[q];fa[q]=ct;fa[ed]=ct;
            for(int i=p;mp[i][c]==q;i=fa[i]){mp[i][c]=ct;}
        }
        void solve(){
            for(int i=1;i<=n;i++){
                int now=1;
                for(int j=i;j<=n;j++){
                    int v=S[j]-'a'+1;
                    now=mp[now][v];
                    pos[i][j]=now;
                }
            }
            for(int i=1;i<=ct;i++)deg[fa[i]]++;
            queue<int>que;
            for(int i=1;i<=ct;i++)if(deg[i]==0)que.push(i);
            while(que.size()){
                int x=que.front();
                int y=fa[x];
                que.pop();
                minpos[y]=min(minpos[x],minpos[y]);
                deg[y]--;
                if(deg[y]==0)que.push(y);
            }
            for(int i=1;i<=n;i++){
                dp[i]=dp[i-1]+a;
                for(int j=2;j<=i;j++){
                    if(minpos[pos[j][i]]<j){
                        dp[i]=min(dp[i],dp[j-1]+b);
                        break;
                    }
                }
            }
            printf("%d
    ",dp[n]);
    
        }
    }sam;
    int main()
    {
        scanf("%d %d %d",&n,&a,&b);
        scanf("%s",S+1);
        for(int i=0;i<maxn*2;i++)sam.minpos[i]=1e9;
        for(int i=1;i<=n;i++)sam.ins(S[i]-'a'+1,i);
        sam.solve();
        return 0;
    }
    

      

  • 相关阅读:
    Linux下安装MySQL5.6
    Linux软件安装管理:rpm与yum
    Linux进程管理
    Linux网络配置
    Linux磁盘分区、挂载
    Django基础之模型层(models.py)、ORM查询之单表查询、多表查询和跨表查询
    Django基础之视图层(views.py)和模板层
    数据的编辑和删除、Django基础之路由层(urls.py)
    小白必会三板斧、静态文件配置、request对象及方法、pycharm和django连接数据库、字段的增删改查和数据的增查
    初识web框架和Django框架
  • 原文地址:https://www.cnblogs.com/carcar/p/11631390.html
Copyright © 2011-2022 走看看