算法练习——Tricky and Clever Password

本文介绍了一个关于回文密码的问题,国王Copa创造了一种由三部分组成的加密密码,其中包含前缀、后缀和中间部分。解密过程中需要找到可能的原始密码,以最大化字符串长度。文章提供了输入输出格式,并展示了样例输入和输出,以及C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

  在年轻的时候,我们故事中的英雄——国王 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; 
}   


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值