Typesetting math: 100%

[JZOJ6347]:ZYB玩字符串(DP+记忆化搜索)


题目描述

  ZYB获得了一个神秘的非空字符串p
  初始时,串S是空的。
  ZYB会执行若干次这样的操作:
  1.选取S中的一个任意的位置(可以是最前面或者最后面)
  2.在这个位置上插入一个完整的p,得到一个新的S
  但是ZYB不小心把p弄丢了。
  他告诉你现在的S是什么,请帮他还原出可能的p
  如果有多个p符合要求,选取长度最短的。
  如果仍然有多解,选取字典序最小的。


输入格式

  从文件string.in中读入数据。
  这道题有多组数据,第一行一个数T,表示数据组数。
  对于每组数据,读入一行字符串,表示S


输出格式

  输出到文件string.out中。
  一共T行,每行一个字符串p,表示对应的答案。


样例

样例输入:

1
hhehellolloelhellolo

样例输出:

hello


数据范围与提示

样例解释:

  S为:
  1.
  2.hello
  3.hhelloello
  4.hhelloelhellolo
  5.hhehellolloelhellolo

数据范围:

  前20%|S|8
  前40%|S|20
  前60%|S|100,|S|300
  另有10%Sp等概率插入可行位置构造出来的。
  另有10%p的长度不超过3
  100%|S|200,T10,|S|666


题解

因为串S肯定有一段连续的是p(最后插进去的),所以可以枚举这个连续的串,再想办法判断就好了。

考虑DP,定义怪怪的,设dp[l][r]表示在当前枚举的长度为len的情况下,区间[l,r]除了前(rl)位匹配了整串前缀以外剩下的部分都匹配了是否可行。

那么考虑转移,设b数组为当前check的这段区间:

  α.dp[l][r]|=dp[l][r1]&(s[j]==b[(ji):多匹配了一位。

  β.dp[l][r]|=dp[i][jk×len]&f[jk×len+1][j]:后面有几段匹配了。

由于β转移的上界为Nlen,所以最终的时间复杂度为Θ(len|N(Nlen+1)×N2×Nlen=Θ(N4)

不过可以对于每一个p,先判断一下其子集合法性,然后使用记忆化搜索即可。

时间复杂度:Θ(N4)(但是远远达不到)。

期望得分:100分。

实际的分:100分。


代码时刻

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
#include<bits/stdc++.h>
using namespace std;
char ch[201];
int n,a[201],b[201],ans[201];
int dp[201][201];
int mod(int x,int y){return x>y?mod(x-y,y):x;}
bool dfs(int x,int l,int r)
{
    if(l>r)return 1;
    if(dp[l][r]!=-1)return dp[l][r];
    for(int mid=r-x;l<=mid;mid-=x)
        if(dfs(x,l,mid)&&dfs(x,mid+1,r))
            return dp[l][r]=1;
    if(a[r]==b[mod(r-l+1,x)])return dp[l][r]=dfs(x,l,r-1);
    return dp[l][r]=0;
}
bool judge(int x){for(int i=1;i<=x;i++)if(ans[i]>b[i])return 1;return 0;}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%s",ch+1);
        n=strlen(ch+1);
        for(int i=1;i<=n;i++)a[i]=ch[i]-'a'+1;
        for(int i=1;i<=n;i++)
        {
            if(n%i)continue;bool res=0;
            memset(ans,0,sizeof(ans));
            for(int j=1;j<=n-i+1;j++)
            {
                memset(dp,-1,sizeof(dp));
                for(int k=1;k<=i;k++)b[k]=a[j+k-1];
                if(dfs(i,1,n)&&(!ans[1]||judge(i)))
                    for(int k=1;k<=i;k++)ans[k]=b[k];
            }
            if(ans[1]){for(int k=1;k<=i;k++)printf("%c",(char)(ans[k]+'a'-1));puts("");break;}
        }
    }
    return 0;
}

rp++

posted @   HEOI-动动  阅读(397)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Linux系统下SQL Server数据库镜像配置全流程详解
· 现代计算机视觉入门之:什么是视频
阅读排行:
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· .NET Core GC压缩(compact_phase)底层原理浅谈
· Winform-耗时操作导致界面渲染滞后
· Phi小模型开发教程:C#使用本地模型Phi视觉模型分析图像,实现图片分类、搜索等功能
· 语音处理 开源项目 EchoSharp
点击右上角即可分享
微信分享提示