zoukankan      html  css  js  c++  java
  • 「SWTR-05」String

    Description

    给定串 (S)(T),每次可以在 (T) 前或后拼接一个 (T) 的子串,求最小步数使得 (T) 变成 (S)

    Solution

    暴力区间dp,剪剪枝有可以做到 50%,考场上没判 -1,怒丢 40pts。

    考虑一个区间 ([l,r]) 能有的转移,假设其能转移到 ([l',r]),其中 (l'in [x,l)),那么实际上我们只需要保留 ([x,l]) 这个区间进行转移,也就是每次找最远的能转移的区间进行转移。考虑为什么是对的。大区间一定是包含小区间的所有子串的,而选择大区间还会使得剩下的串更小,不会使得答案更劣。那么现在的问题就是快速处理出一个区间最多能扩展到哪儿。类比于上面的道理,记一个区间 ([l,r]) 向右能扩展的最大长度为 (f_{l,r}),那么一定有 (f_{l,r}geq f_{l+1,r}),所以直接从 (f_{l+1,r}) 开始枚举,新增的能匹配的一定是以 (l) 为起点的串,可以用 Hash 扩展。

    计算答案可以用 bfs,因为每次转移增量都是一。

    #include<stdio.h>
    #include<string.h>
    #include<queue>
    using namespace std;
    
    typedef long long ll;
    
    const int Bs=233;
    const int N=5e3+7;
    const int Mod=998244353;
    
    struct Seg{
        int l,r;
        Seg(int l_=0,int r_=0):l(l_),r(r_){}
    };
    
    queue<Seg> Q;
    char s[N],t[N];
    ll pw[N],hs=0,Hs[N];
    int toL[N][N],toR[N][N],dp[N][N];
    
    inline ll Get(int l,int r){
        return (Hs[r]-Hs[l-1]*pw[r-l+1]%Mod+Mod)%Mod;
    }
    
    int main(){
    //    freopen("cutstring.in","r",stdin);
    //    freopen("cutstring.out","w",stdout);
        scanf("%s%s",s+1,t+1);
        int n=strlen(s+1),m=strlen(t+1); pw[0]=1;
        for(int i=1;i<=n;i++)
            pw[i]=pw[i-1]*Bs%Mod,
            Hs[i]=(Hs[i-1]*Bs%Mod+s[i])%Mod;
        for(int i=1;i<=m;i++)
            hs=(hs*Bs%Mod+t[i])%Mod;
        for(int l=1;l<=n;l++){
            int ret=1;
            for(int r=l;r<=n;r++){
                while((l-ret>=1&&r-l+1>=ret)&&Get(r-ret+1,r)==Get(l-ret,l-1)) ret++;
                toL[l][r]=ret-1;
            }
        }
        for(int r=n;r;r--){
            int ret=1;
            for(int l=r;l;l--){
                while((r+ret<=n&&r-l+1>=ret)&&Get(l,l+ret-1)==Get(r+1,r+ret)) ret++;
                toR[l][r]=ret-1;
            }
        }
    //    for(int i=1;i<=n;i++)
    //        for(int j=i;j<=n;j++)
    //            printf("%d %d %d %d
    ",i,j,toL[i][j],toR[i][j]);
        memset(dp,-1,sizeof(dp));
        for(int i=1;i<=n;i++)
            if(Get(i,i+m-1)==hs) Q.push(Seg(i,i+m-1)),dp[i][i+m-1]=0;
        while(!Q.empty()){
            Seg t=Q.front(); Q.pop();
        //    printf("%d %d %d
    ",t.l,t.r,dp[t.l][t.r]);
            if(toL[t.l][t.r]){
                const int del=toL[t.l][t.r];
                if(dp[t.l-del][t.r]==-1){
                    dp[t.l-del][t.r]=dp[t.l][t.r]+1;
                    Q.push(Seg(t.l-del,t.r));
                }
            }
            if(toR[t.l][t.r]){
                const int del=toR[t.l][t.r];
                if(dp[t.l][t.r+del]==-1){
                    dp[t.l][t.r+del]=dp[t.l][t.r]+1;
                    Q.push(Seg(t.l,t.r+del));
                }
            }
        }
        printf("%d",dp[1][n]);
    }
    
  • 相关阅读:
    Centos 5.5 Lamp源码包安装编译 新风宇宙
    Linux系统日志管理 新风宇宙
    ubuntu设置时区,网上同步时间 新风宇宙
    ubuntu vim输入中文设置(SecureCRT下) 新风宇宙
    DIV+CSS容易犯的十个错误 新风宇宙
    apache性能优化 新风宇宙
    java里面main函数为什么要用static修饰
    如何设计mysql数据库和数据表
    PHP 图片验证码
    PHP免费空间选择方法概述
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/15395196.html
Copyright © 2011-2022 走看看