题解 CF1109B Sasha and One More Name
先考虑Impossible
的情况。
显然如果所有字符全一样那肯定无解。
还有一种情况就是 \(n\) 为奇数且除了中间的一个字符其余全部相等,也无解。
理由很简单,剩下的字符全相等,由于新串是回文的,所以和原来的串一定是同一个串。
下面我们分奇偶性来讨论。
- \(n\) 为奇数
这种情况下,答案不大于 \(2\) ,因为除了中间的旁边的字符不全相等,所以一定有中间的一段,他的两边不是回文串,直接切两下就行了。
同时,答案也不可能小于 \(2\) ,因为如果一刀就行的话,由于新串回文,且长度为奇数,所以手动模拟一下就能看出,这样一定所有字符都相等才能让新串和原串全都回文,而这时答案为Impossible
,不符合题意。
所以当 \(n\) 为奇数时,答案为 \(2\) 。
- \(n\) 为偶数
这时稍微麻烦一点,分两种情况。
我们取串的前一半,由于是回文长度为偶数的串,所以后一半一样的不用管就可以了。
- 取出的这个串不是回文串,这时直接一刀把原串从中间分成两段即可,答案为 \(1\) 。
- 取出的串是回文串,这样我们可以把整个原串分成两半,因为这一半回文,所以求出当串长为 \(\frac{n}{2}\) 时的答案。如果是 \(2\) 就对称的切一刀,原串答案仍为 \(2\) 。如果是 \(1\) 就还在那个位置切,原串答案仍为 \(1\) 。所以新串的答案即为原串的答案,递归处理即可。
时间复杂度 \(O(n\log n)\) 。
代码
#include<bits/stdc++.h>
#define re register
#define N 1001001
#define MAX 2001
#define inf 1e18
using namespace std;
typedef long long ll;
typedef double db;
inline void read(re ll &ret)
{
ret=0;re ll pd=0;re char c=getchar();
while(!isdigit(c)){pd|=c=='-';c=getchar();}
while(isdigit(c)){ret=(ret<<1)+(ret<<3)+(c&15);c=getchar();}
ret=pd?-ret:ret;
return;
}
ll t,n;
char s[N];
signed main()
{
t=1;
while(t--)
{
scanf("%s",s+1);
n=strlen(s+1);
re bool flag=true;
for(re int i=2;i<=(n>>1);i++)
flag&=(s[i]==s[i-1]);
if(flag)
{
puts("Impossible");
continue;
}
start:
flag=true;
for(re int i=1;(i<<1)<=n;i++)
{
if(s[(n>>1)-i+1]!=s[i])
flag=false;
}
if(!flag&&(n&1))
{
puts("2");
continue;
}
else if(!flag&&!(n&1))
{
puts("1");
continue;
}
else if(flag&&(n&1))
{
puts("2");
continue;
}
else if(flag&&!(n&1))
{
n>>=1;
goto start;//即为前文所说的递归,goto简化代码
}
}
exit(0);
}