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


    题目描述

      $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|\leqslant 8$
      前$40\%$:$|S|\leqslant 20$
      前$60\%$:$|S|\leqslant 100,\sum|S|\leqslant 300$
      另有$10\%$:$S$是$p$等概率插入可行位置构造出来的。
      另有$10\%$:$p$的长度不超过$3$。
      $100\%$:$|S|\leqslant 200,T\leqslant 10,\sum|S|\leqslant 666$


    题解

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

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

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

      $\alpha.dp[l][r]|=dp[l][r-1]\&(s[j]==b[(j-i)%len+1])$:多匹配了一位。

      $\beta.dp[l][r]|=dp[i][j-k\times len]\&f[j-k\times len+1][j]$:后面有几段匹配了。

    由于$\beta$转移的上界为$\frac{N}{len}$,所以最终的时间复杂度为$\Theta(\sum\limits_{len|N}(N-len+1)\times N^2\times\frac{N}{len}=\Theta(N^4)$。

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

    时间复杂度:$\Theta(N^4)$(但是远远达不到)。

    期望得分:$100$分。

    实际的分:$100$分。


    代码时刻

    #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++

  • 相关阅读:
    解决IE输入框文本输入时的 X
    CSS3发光输入框
    去掉超链接或按钮点击时出现的虚线边框
    [LeetCode][JavaScript]Add and Search Word
    [LeetCode][JavaScript]Lowest Common Ancestor of a Binary Search Tree
    [LeetCode][JavaScript]Palindrome Linked List
    [LeetCode][JavaScript]Number of Digit One
    [LeetCode][JavaScript]Implement Queue using Stacks
    [LeetCode][JavaScript]Implement Trie (Prefix Tree)
    [LeetCode][JavaScript]Power of Two
  • 原文地址:https://www.cnblogs.com/My-tiantian/p/11850230.html
Copyright © 2020-2023  润新知