题目大意
给定一个字串集为
数据范围
题解
这道题感觉非常的好玩,不知道为什么要强行说是一个分类讨论题。。。
首先我们将最终得到的最长回文串的回文中心进行分类讨论:
1. 回文中心没有被排序
2. 回文中心是排序后调过来的,并且存在某个前缀,使得其没有被排序
注意上面的分类没有考虑到一种回文串整个都是被排序了得情况,我们可以最后将
接下来我们考虑排序的区间都是在右边的,也就是不会对回文串的前面排序,对于前面排序的情况我们可以整个串取反来做。
回文中心没有被排序
先枚举回文中心,设为位置i
设
那么我们相当于可以设两个指针
但有一个值得注意的小细节,就是假如当前
这里的复杂度为
回文中心被排序
设最大的没有被排序的位置为
关键还是代码吧。。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 3005;
int F[MAXN][MAXN],S[MAXN],N,C;
void Get_F()
{
memset(F,0,sizeof F);
//F[i][j] max(S[i - l + 1..i] = S[j..j + l - 1])
for(int i = 1;i <= N;i ++)
for(int j = N;j >= i;j --)
if (F[i - 1][j + 1] >= 0 && S[i] == S[j]) F[i][j] = F[i - 1][j + 1] + 1;
}
int TreatR(int lr,int cent,int rl)
{
if (!lr || rl > N) return 0;
static int Cnt[MAXN],Cur[MAXN],Stack[MAXN][2];
int top = 0;
memset(Cnt,0,sizeof Cnt),memset(Cur,0,sizeof Cur);
for(int u = lr;u;u --)
{
++ Cnt[S[u]];
if (S[u] >= Stack[top][0]) Stack[++ top][0] = S[u],Stack[top][1] = Cnt[S[u]]; else
break;
}
int MiLen = 0,NeedLen = 0,LimLen = top,tmp = 0;
for(int rr = rl;rr <= N;rr ++)
{
if (S[rr] < cent) break; else
if (S[rr] == cent) ++ MiLen; else
{
++ Cur[S[rr]];
if (Cnt[S[rr]] >= Cur[S[rr]])
{
while (NeedLen + 1 <= top)
{
int val = Stack[NeedLen + 1][0];
if (Cur[val] >= Stack[NeedLen + 1][1]) ++ NeedLen; else break;
}
} else
{
while (LimLen)
{
int val = Stack[LimLen][0];
if (val > S[rr]) -- LimLen; else break;
}
}
}
int cl = min(NeedLen,LimLen);
tmp = max(tmp,cl * 2 + MiLen);
if (rr - rl + 1 == cl + MiLen) tmp = max(tmp,cl * 2 + MiLen + 2 * F[lr - cl][rl + cl + MiLen]);
}
return tmp;
}
int Calc()
{
Get_F();
//calc middle as a position
int tmp = 0;
for(int i = 1;i <= N;i ++)
{
int lr = i,rl = i,d = F[i][i];
lr -= d,rl += d;
tmp = max(tmp,TreatR(lr,-1,rl) + 2 * d - 1);
}
//calc middle as a middle
for(int i = 1;i < N;i ++)
{
int lr = i,rl = i + 1,d = F[i][i + 1];
lr -= d,rl += d;
tmp = max(tmp,TreatR(lr,-1,rl) + 2 * d);
}
//calc those when the sorted make difference
for(int i = 1;i <= N;i ++)
{
int cent = -1;
for(int j = i + 1;j <= N;j ++)
if (S[j] < S[i]) {cent = S[j];break;}
tmp = max(tmp,TreatR(i,cent,i + 1));
}
return tmp;
}
void Work()
{
static int Bak[MAXN];
for(int i = 1;i <= N;i ++) scanf("%d", &S[i]);
int ans = Calc();
memcpy(Bak,S,sizeof Bak);
for(int i = 1;i <= N;i ++) S[i] = C - S[i] + 1;
reverse(S + 1,S + N + 1);
ans = max(ans,Calc());
memcpy(Bak,S,sizeof Bak);
int c = 0,cr = 0;
sort(S + 1,S + N + 1);
for(int i = 1;i <= N;i ++)
if (S[i] != S[i - 1]) ans = max(ans,cr),cr = 1; else ++ cr;
ans = max(ans,cr);
printf("%d\n", ans);
}
int main()
{
while (scanf("%d%d", &N, &C) != EOF) Work();
return 0;
}