loj6158 A+B Problem (扩展KMP)

题目:

https://loj.ac/problem/6158

分析:

先把S串逆置,就是从低位向高位看

我们再弄个T串,S串前面有x个连续的0,那么T串前面也有x个连续的0

第x+1位,满足S[x+1]+T[x+1]=10

后面的位置,均满足S[j]+T[j]=9

然后我们发现S的每一个后缀S[i]与T串进行匹配,求个最长的前缀就是当前在这个位置劈开的结果

这个是个典型的扩展KMP的应用,即对于S、T串,求S的每个后缀S[i]与T的最长公共前缀

本题有几点细节

1、因为最高位之前的那些位置都是0,所以在S串的后面,需要加上一些0

2、要注意当某个S[i]和T的最长公共前缀超过了i的位置,那么超过i的那些位置并不是我们想要的,实际上,那些应该是99999999……或者000000........

所以可以预处理出S的每一位后面有多少连续的0和多少个连续的9

 1 #include<cstring>
 2 #include<algorithm>
 3 #include<cstdio>
 4 using namespace std;
 5 const int maxn=1e6;
 6 char S[2*maxn+50],T[maxn+50];//S是母串,T是子串
 7 int len1,len2;
 8 int next[maxn+50],extend[2*maxn+50];//extend[i]表示S[i..len1-1]和T的最长公共前缀的长度,next[i]表示T[i..len2-1]和T的最长公共前缀的长度
 9 int num9[maxn+50];
10 int num0[maxn+50];
11 void getnext()
12 {
13     next[0]=len2;
14     int j=0;
15     while(j+1<len2&&T[j]==T[j+1]) ++j;
16     next[1]=j;
17     int k=1;
18     for(int i=2;i<len2;++i)
19     {
20         int p=k+next[k]-1,l=next[i-k];
21         if(i+l<p+1) next[i]=l;
22         else
23         {
24             j=max(p-i+1,0);
25             while(i+j<len2&&T[i+j]==T[j]) ++j;
26             next[i]=j;
27             k=i;
28         }
29     }
30 }
31 void ekmp()
32 {
33     int j=0;
34     while(j<len1&&j<len2&&S[j]==T[j]) ++j;
35     extend[0]=j;
36     int k=0;
37     for(int i=1;i<len1;++i)
38     {
39         int p=k+extend[k]-1,l=next[i-k];//p表示到达的最远位置,k是对应最远位置的i
40         if(i+l<p+1) extend[i]=l;
41         else
42         {
43             j=max(p-i+1,0);
44             while(i+j<len1&&j<len2&&S[i+j]==T[j]) ++j;
45             extend[i]=j;
46             k=i;
47         }
48     }
49 }
50 int main()
51 {
52
53     while (scanf("%s",S)!=EOF)
54     {
55         len1=strlen(S);
56         for(int i=0;i<len1/2;++i) swap(S[i],S[len1-i-1]);
57         int i=0;
58         for(i=0;S[i]==‘0‘;++i) T[i]=‘0‘;
59         T[i]=‘9‘+1-S[i]+‘0‘;
60         ++i;
61         for(i;i<len1;++i)
62             T[i]=‘9‘-S[i]+‘0‘;
63         T[len2=len1]=‘\0‘;
64         for(int i=len1;i<len1+len2;++i) S[i]=‘0‘;
65         S[len1+len2]=‘\0‘;
66         len1=strlen(S);
67         memset(num9,0,sizeof(num9));
68         memset(num0,0,sizeof(num0));
69         for(int i=len2-1;i>=0;--i)
70         {
71             if(S[i+1]!=‘9‘) num9[i]=0;else num9[i]=num9[i+1]+1;
72             if(S[i+1]!=‘0‘||i==len2-1) num0[i]=0;else num0[i]=num0[i+1]+1;
73         }
74         memset(next,0,sizeof(next));
75         memset(extend,0,sizeof(extend));
76         getnext();
77         ekmp();
78         int ans=0;
79         for(int i=1;i<len2;++i)
80         {
81             if(extend[i]>=i)
82             {
83                 if(S[i]==‘0‘&&num0[i]>=i-1) ans=max(ans,num0[i+i-1]+i);
84                 else ans=max(ans,num9[i+i-1]+i);
85             }
86             else
87              ans=max(ans,extend[i]);
88         }
89         printf("%d\n",ans);
90     }
91     return 0;
92 }

时间: 2024-11-05 00:45:27

loj6158 A+B Problem (扩展KMP)的相关文章

扩展KMP - HDU 4333 Revolving Digits

Revolving Digits Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=4333 Mean: 给你一个字符串,你可以将该字符串的任意长度后缀截取下来然后接到最前面,让你统计所有新串中有多少种字典序小于.等于.大于原串. analyse: KMP的经典题. 首先我们将原串扩展成两倍,算一遍扩展KMP(自匹配),时间复杂度O(n). 这样一来,我们就得到了eKMP[i],eKMP[i]代表s[i...len-1]与s的最长

HDU 6153 A Secret(扩展KMP模板题)

A Secret Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others) Total Submission(s): 2523    Accepted Submission(s): 934 Problem Description Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,w

POJ--1699--Best Sequence【扩展KMP+DFS】

链接:http://poj.org/problem?id=1699 题意:给出n个字符串,求他们相连的最小长度,如果首尾字母相同则可以共用相同部分,比如两个串ABCDEF和DEFGHI,他们相连为ABCDEFGHI,最小长度为9,中间的DEF部分共用了. 思路:由于数据量较小,首先对每两个字符串a,b用扩展KMP求出a连在b之后可以共用的长度,用数组B[i][j]表示第j个字符串连接在第i个字符串后面能共用的最大长度. 1.在扩展KMP函数中求子串a和母串b的公共前缀数组ret[i](子串.母串

扩展KMP --- HDU 3613 Best Reward

Best Reward Problem's Link:   http://acm.hdu.edu.cn/showproblem.php?pid=3613 Mean: 给你一个字符串,每个字符都有一个权值(可能为负),让你将这个字符串分成两个字串,使得这两个子串的价值之和最大.一个子串价值的计算方法:如果这个子串是回文串,那么价值就是这个子串所有字符权值之和:否则价值为0. analyse: 经典的扩展KMP算法运用. 假设输入串为s,那么我们首先:strcpy(s1,s)     ;      

KMP &amp; 扩展KMP &amp; Manacher 专题

KMP & 扩展KMP & Manacher  专题 先来模版: void getNext(int *b,int m) { Next[0]=-1; int i=0,j=-1; while(i<m&&j<m){ if(j==-1||b[i]==b[j]) Next[++i]=++j; else j=Next[j]; } } int kmp(int *a,int *b,int n,int m) { getNext(b,m); int i=0,j=0; while(i

HDU 6153 A Secret(扩展kmp)

A Secret Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others)Total Submission(s): 1530    Accepted Submission(s): 570 Problem Description Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,wh

字符串(扩展KMP):HDU 4333 Revolving Digits

Revolving Digits Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24729    Accepted Submission(s): 5381 Problem Description One day Silence is interested in revolving the digits of a positive int

扩展KMP,附上例题(HDU - 4333 Revolving Digits)

给出模板串S和串T,长度分别为Slen和Tlen,在线性时间内,对于每个S[i](0<=i<Slen),求出S[i..Slen-1]与T的 最长公共前缀长度,记为extend[i],extend[i]存放s[i]开始与T的最长公共前缀长度. 例子 a a a a a a a b b b a a a a a c extend 5 4 3 2 1 0 0 0 0 0 HDU - 4333 Revolving Digits Time Limit: 3000/1000 MS (Java/Others)

A - A Secret (扩展kmp)

题目链接:https://cn.vjudge.net/contest/283743#problem/A 题目大意:给你字符串s1和s2,然后问你s2的每一个后缀在s1中出现的次数之和(可重叠). 具体思路:首先将s1和s2翻转过来,这样的话就把后缀问题转换成了求前缀的问题.举个例子,s1="abcd",s2="cd",将两个字符串都翻转之后,s1变成了"dcba",s2变成了"dc",然后就按照扩展kmp的方法求出s2的每一个