博客观赏效果更佳
(noi.ac题面被改过了,题意是一样的)
题意简述
给你一个字符串
S
S
S,长度
1
e
6
1e6
1e6。
S
S
S的一个
k
k
k个串的划分
a
1
,
a
2
.
.
.
a
k
a_1,a_2...a_k
a1,a2...ak,满足:对于任意的
i
i
i,
a
i
=
a
k
−
i
+
1
a_i=a_{k-i+1}
ai=ak−i+1,这就是
S
S
S的一个“回文划分”,它被分成了
k
k
k块。
请你求
S
S
S中被分成的块数最多的一个回文划分,输出这个最多的块数。
比如样例中的“bonobo”这个串,最大的划分就是“bo/no/bo”,3块。
思路框架
从两边往中间,每次找最短的串,使得它在前面和后面同时出现(哈希判断)。
到最后,如果 n n n为奇数,或者中间一块不能再分了,就把答案 + 1 +1 +1(中间一块单独划分出来)。
代码
#include <bits/stdc++.h>using namespace std;
namespace Flandre_Scarlet
{
#define N 1666666
#define hint unsigned long long //自然溢出的哈希
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
#define p_b push_back
#define sz(a) ((int)a.size())
#define iter(a,p) (a.begin()+p)
void R1(int &x)
{
x=0;char c=getchar();int f=1;
while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=(f==1)?x:-x;
}
void Rd(int cnt,...)
{
va_list args;
va_start(args,cnt);
F(i,1,cnt)
{
int* x=va_arg(args,int*);R1(*x);
}
va_end(args);
}
char a[N]; int n;
void Input()
{
scanf("%s",a+1); n=strlen(a+1);
}
void Soviet()
{
hint base=79;
hint s1=0,s2=0,b=1;
int ans=0;
F(i,1,n/2)
{
s1=s1*base+a[i]; //在s1后面加入a[i]
s2=s2+a[n-i+1]*b; //在s2的前面加入a[i]
b*=base;
if (s1==s2) {ans+=2;s1=s2=0,b=1;} //找到第一个满足条件就记录答案
}
if (n%2 or s1) ++ans;
printf("%d\n",ans);
}
#define Flan void
Flan IsMyWife()
{
int t;R1(t);
while(t--)
{
Input();
Soviet();
}
}
}
int main(){
Flandre_Scarlet::IsMyWife();
getchar();getchar();
return 0;
}