• Codeforces 109D String Transformation 字符串 哈希 KMP


    原文链接https://www.cnblogs.com/zhouzhendong/p/CF109D.html

    题目传送门 - CF109D

    题意

      给定两个字符串 $a,b$ ,求一组 $i,j$ 使得 $f(a,i,j)=b$ 。如果无解输出 "-1 -1" ,如果多组解,输出 i 尽量大的;如果 i 相同,输出 j 尽量小的。

      其中 $f(s,i,j) = s[i+1 cdots j-1] + r(s[0 cdots i]) + r(s[jcdots n-1])$ 。 $n$ 为串长。其中 $s[icdots j]$ 表示 串 $s$ 的 $i$ 至 $j$ 个位置构成的子串,+ 运算定义为字符串顺序拼接,$r(s)$ 表示 $s$ 翻转后得到的串。

      $|a|,|b| leq 10^6$

    题解

      那个最大最小问题不大,我们来看看如何找一组解。

      首先,讲 a 串翻转。则问题变成了 $r(a[i+1]cdots a[j-1])+a[0cdots i] + a[jcdots n-1]=b$ 的 $(i,j)$ 。这个问题,只需要枚举 $j$ ,然后判定是否可以行即可。

      对于 $r(a[i+1]cdots a[j-1])$ 与 $b$ 的最大匹配长度,可以二分 + 哈希。

      对于以 b 串第 $j-1$ 个位置结尾的子串中与 $a$ 的前缀的匹配长度最大为多少,直接 KMP 。

      如果这两个长度大于 $j-1$ ,那么就可行。

      那个什么最大最小的,随便弄一弄就好了。

      注意我们求出来的翻转后的 a 串的答案,最后还要变换一下。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ULL;
    const int N=1000005*2;
    char a[N],b[N];
    int n,Next[N],len[N];
    ULL Ha[N],Hb[N],Fac[N],T=233;
    ULL Get_Hash(ULL *Ha,int L,int R){
    	if (L>R)
    		L=n*2-L+1,R=n*2-R+1;
    	return Ha[R]-Ha[L-1]*Fac[R-L+1];
    }
    void KMP(char *a,char *b,int n){
    	for (int i=2,k=0;i<=n;Next[i]=k+=(a[k+1]==a[i]),i++)
    		while (k>0&&a[k+1]!=a[i])
    			k=Next[k];
    	for (int i=1,k=0;i<=n;len[i]=k+=(a[k+1]==b[i]),i++)
    		while (k>0&&a[k+1]!=b[i])
    			k=Next[k];
    }
    int Get(int j){
    	int L=1,R=j-1,mid,k1=0;
    	while (L<=R){
    		mid=(L+R)>>1;
    		if (Get_Hash(Hb,1,mid)==Get_Hash(Ha,j-1,j-mid))
    			L=mid+1,k1=mid;
    		else
    			R=mid-1;
    	}
    	return k1+len[j-1]<j-1?-1:len[j-1];
    }
    int main(){
    	gets(a+1),gets(b+1);
    	n=strlen(a+1);
    	if (strlen(b+1)!=n)
    		return puts("-1 -1"),0;
    	reverse(a+1,a+n+1);
    	for (int i=n+1;i<=n*2;i++)
    		a[i]=a[n*2-i+1],b[i]=b[n*2-i+1];
    	KMP(a,b,n);
    	for (int i=Fac[0]=1;i<=n*2;i++){
    		Fac[i]=Fac[i-1]*T;
    		Ha[i]=Ha[i-1]*T+a[i];
    		Hb[i]=Hb[i-1]*T+b[i];
    	}
    	int ansi=10000000,ansj=10000000,d=-1;
    	for (d=n;d>1;d--)
    		if (a[d]!=b[d])
    			break;
    	for (int i=-1,j=d+1;j<=n&&!~i;j++)
    		if (~(i=Get(j)))
    			ansi=i,ansj=j;
    	if (ansj==10000000)
    		ansi=ansj=-1;
    	else
    		ansi=n-ansi,ansj=n-ansj;
    	printf("%d %d
    ",ansj,ansi);
    	return 0;
    }
    

      

  • 相关阅读:
    cs231n--详解卷积神经网络
    Spring 2017 Assignments2
    深度神经网络基础
    cs231n官方note笔记
    Spring 2017 Assignments1
    问题
    win7下解决vs2015新建项目,提示“未将对象引用设置到引用实例“的问题
    项目二:人脸识别
    ubutu强制关闭应用程序的方法
    将caj文件转化为pdf文件进行全文下载脚本(ubuntu下亲测有用)
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/CF109D.html
Copyright © 2020-2023  润新知