题目来源
题目描述
题目解析
这题其实是50Nod上的一道原题,还是51Nod上说的清楚一些,这题的描述我看了半天都没有看懂
题目翻译:
- 给你一个字符串,它的长度是M,它是非回文的,它只由前N个小写字母组成(不一定全部用),而且不包含长度大于等于2的回文子串
- 要求你返回字典序比s大的,也只能使用前N个小写字母,而且长度是M的字符串
题目分析:
- “字符串不包含任何长度大于等于2的回文串”怎么理解
- 没有长度为2或者是长度大于2的回文串
- 如果一个字符串没有长度为2的回文串,也就是说整个字符串没有两个相邻的字符是相同的
- 如果一个字符串没有长度为3的子回文串,那么就能保证整个字符串没有两个间隔一个字符的两个字符是相同的。
- 那么换句话说,综上两点,就是在说没有任意三个相邻的字符是相同的,只要满足这一点,那么这个字符串一定是一个可行串。
- 即满足:s[i]!=s[i-1] i>=1;s[i]!=s[i-2] i>=2的串都是才是我们要找的
- 下一个满足的字符串一定是尽量靠右的字符才能得到(字典序)
- 所以我们从最右边开始找,假设当前是第i位,如果它增加之后满足和i-1,i-2位均不相同,那么最小的肯定是从这里开始改变的(因为前缀没有回文字串,所以改变i位后的串也不会有)
- 因此,我们从最后面开始暴力处理:
①如果当前位子<0,那么说明不存在可行解,如果当前位子==n,那么说明存在解。
②对应当前位子的字符字典序+1,判断一下当前位子和前边两个位子的字符是否相等,如果存在相等,说明当前解不可行,继续字典序+1.
如果不存在相等,那么当前位子是一个可行解,将位子向后移一位。
③若在过程②中,当前位子的字符字典序加到了p还是不可行,那么我们将位子向前移一位,去处理之前为可行之后,再回到这个位子重新暴力处理。
举个例子:
#include <utility>
#include <vector>
#include <map>
#include <set>
#include <iostream>
#include <queue>
using namespace std;
#include<stdio.h>
#include<string.h>
using namespace std;
int judge(std::string a, int pos)
{
if(pos>=1&&a[pos-1]==a[pos])return 0;
if(pos>=2&&a[pos-2]==a[pos])return 0;
return 1;
}
std::string process(std::string a, int n, int m){
std::string ans;
int pos=n-1;
while(1)
{
if(pos==n)
{
ans = a;
break;
}
if(pos<0)
{
ans = "NO";
break;
}
if(a[pos]-'a'+1==m)
{
a[pos]='a'-1;
pos--;
}
else
{
int tmp=(a[pos]-'a'+1)%m;
a[pos]='a'+tmp;
if(judge(a, pos)==1)pos++;
}
}
return ans;
}
int main()
{
std::string a = "abcd";
int n = 4,m = 4;
std::cout << process(a, n, m);
}