您的位置:首页 > 其它

算法练习——Tricky and Clever Password

2017-03-13 21:59 337 查看
问题描述
  在年轻的时候,我们故事中的英雄——国王 Copa——他的私人数据并不是完全安全地隐蔽。对他来说是,这不可接受的。因此,他发明了一种密码,好记又难以破解。后来,他才知道这种密码是一个长度为奇数的回文串。

  Copa 害怕忘记密码,所以他决定把密码写在一张纸上。他发现这样保存密码不安全,于是他决定按下述方法加密密码:他选定一个整数 X ,保证 X 不小于 0 ,且 2X 严格小于串长度。然后他把密码分成 3 段,最前面的 X 个字符为一段,最后面的 X 个字符为一段,剩余的字符为一段。不妨把这三段依次称之为 prefix, suffix, middle 。显然, middle 的长度为一个大于 0 的奇数,且 prefix 、suffix 的长度相等。他加密后的密码即为 A + prefix + B + middle
+ C +suffix ,其中 A 、 B 、 C 是三个由 Copa 选定的字符串,且都有可能为空, + 表示字符串相连。

  许多年过去了。Copa 昨天找到了当年写下加密后字符串的那张纸。但是,Copa 把原密码、A、B、C 都忘了。现在,他请你找一个尽量长的密码,使得这个密码有可能被当年的 Copa 发明、加密并写下。
输入格式
  输入包含一个只含有小写拉丁字母的字符串,长度在 1 到 10^5 之内。
输出格式
  第一行包含一个整数 k ,表示你找到的原密码分成的 3 个部分中有多少个非空字符串。显然 k in {1, 3} 。接下来 k 行,每行 2 个用空格分开的整数 x_i l_i ,表示这一部分的起始位置和长度。要求输出的 x_i 递增。

  起始位置 x_i 应该在 1 到加密后的字符串长度之间。 l_i 必须是正整数,因为你只要输出非空部分的信息。 middle 的长度必须为奇数。

  如果有多组答案,任意一组即可。提示:你要最大化的是输出的 l_i 的总和,而不是 k 。
样例输入
abacaba
样例输出
1

1 7
样例输入
axbya
样例输出
3

1 1

2 1

5 1
样例输入
xabyczba
样例输出
3

2 2

4 1

7 2
数据规模和约定
  对于 10% 的数据: n <= 10

  对于 30% 的数据: n <= 100

  对于 100% 的数据: n <= 100000

  存在 20% 的数据,输出文件第一行为 1 。

C++代码如下:
#include<stdio.h>
#include<string.h>
#define INF 0x3f3f3f3f
char s[100010], s1[200010];
int mana[100010], L, next[200010],match[100010], r[100010];
int min(int x, int y)
{
return x<y?x:y;
}
void getmana()
{
mana[0] = 0;
int i;
int id = 0, right = 0;
for(i = 1; i < L-1; ++i)
{
if(right > i)
mana[i] = min(mana[2*id - i], right - i);
else
mana[i] = 0;
while(s[i+mana[i]+1] == s[i-mana[i]-1] && (i+mana[i]+1) < L && (i-mana[i]-1) >= 0)
mana[i]++;
if(mana[i]+i > right)
{
id = i;
right = mana[i]+i;
}
}
}
void getnext(char *temp)
{
memset(next, 0, sizeof(next));
next[0] = -1;
int i = 0, j = -1;
while(temp[i])
{
if(j == -1 || temp[i] == temp[j])
{
i++;
j++;
next[i] = j;
}
else
j = next[j];
}
}

int main()
{
int i, j, k, l;
while(gets(s) != NULL)
{
L = strlen(s);
getmana();
for(i = L-1; i >= 0; --i)
s1[L-1-i] = s[i];
s1[L] = '#';
s1[L+1] = '\0';
strcat(s1,s);
getnext(s1);
for(i = L+1; i <= 2*L+1; ++i)
match[i-L-1] = next[i];
memset(r, -1, sizeof(r));
for(i = 1; i <= L; ++i)
{
if(match[i] > match[i-1])
r[match[i]-1] = i-1;
else
match[i] = match[i-1];
}
for(i = 1; i < L; ++i)
{
if(r[i] == -1)
r[i] = r[i-1];
//      printf("%d ",r[i]);
}
//  printf("\n");
int ans[3][2] = {0}, max = 0;
bool ok = true;
for(i = 1; i < L-1; ++i)//the lengthmust bigger than 3
{
j = i+mana[i]+1;
if(j >= L || i-mana[i] <= 0)
j = L;
else
{
if(r[L-j-1] == -1)
j = L;
else
{
if(r[L-j-1] >=i-mana[i])
j = L -match[i-mana[i]];
else
j = L -match[r[L-j-1]+1];
}
}
if(j < L)
{
if(2*(L-j) + mana[i]*2 + 1 >max)
{
max = 2*(L-j) + mana[i]*2 +1;
ans[0][0] = r[L-j-1] - L +j + 1;
ans[0][1] = L-j;
ans[1][0] = i-mana[i];
ans[1][1] =2*mana[i]+1;
ans[2][0] = j;
ans[2][1] = L-j;
ok = false;
//      printf("1 %d\n",max);
}
}
else
{
if(2*mana[i]+1 > max)
{
max = 2*mana[i]+1;
ok = true;
ans[1][0] = i-mana[i];
ans[1][1] =2*mana[i]+1;
}
}
}
if(ok)
{
if(ans[1][1] == 0)
ans[1][1] = 1;
printf("1\n%d %d\n", ans[1][0]+1, ans[1][1]);
}
else
{
printf("3\n");
printf("%d %d\n", ans[0][0]+1, ans[0][1]);
printf("%d %d\n", ans[1][0]+1, ans[1][1]);
printf("%d %d\n", ans[2][0]+1, ans[2][1]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: