专栏文章
题解:P14412 [JOISC 2015] AAQQZ
P14412题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min6qjll
- 此快照首次捕获于
- 2025/12/01 21:28 3 个月前
- 此快照最后确认于
- 2025/12/01 21:28 3 个月前
感觉吃了一坨。
题意
给定一个长为 的数组,选择一个区间 进行排序,最大化排序后最长回文子串的长度。
。
题解
首先令答案对原串最长回文子串和众数个数取 ,这两种情况是平凡的。
之后有两种情况:
- 回文中心在排序区间外。
- 回文中心在排序区间的开头(或结尾)极长相等连续段内(例如 )
对于第一种情况,设排序区间在右,枚举回文中心,向两侧扩展后枚举排序区间,当然你可以平衡树维护哈希,但是有简单做法:对左侧最长不升子序列开桶,由于排序后区间是上升的,所以可以维护值域指针 表示匹配到了哪个值,最后判断能否向外扩展即可。
对于第二种情况,枚举回文中心不好做,考虑枚举排序区间起点 ,对以 结尾的最长不升子序列开桶,此时往后枚举 ,当遇到 的数时开始记贡献,匹配方式与第一种情况相同,唯一区别是不匹配最小值。
。
CPP#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,V,ans;
int a[3005];
int cnt[3005];
int lcp[3005][3005];
int cntl[3005],cntr[3005];
void solve1(int l,int r){
if(l<1||r>n) return;
memset(cntl,0,sizeof(cntl));
memset(cntr,0,sizeof(cntr));
cntl[a[l]]++;
int Lpos=l-1;
for(int i=l-1;i>=1;i--){
if(a[i]>=a[i+1]){
cntl[a[i]]++;
Lpos=i;
}else break;
}
int ptr=0,len=0,mx=0;
for(int R=r;R<=n;R++){
cntr[a[R]]++;
mx=max(mx,a[R]);
if(a[R]<=ptr){
while(ptr>=a[R]){
len-=cntl[ptr];
ptr--;
}
}
while(ptr<=V&&cntl[ptr+1]==cntr[ptr+1]) len+=cntl[ptr+1],ptr++;
if(len==R-r+1&&len==l-Lpos+1) ans=max(ans,(R-r+1)*2+r-l-1+2*lcp[l-(R-r+1)][R+1]);
else ans=max(ans,r-l-1+2*len+2*min(cntl[ptr+1],cntr[ptr+1]));
}
}
void solve2(int l){
memset(cntl,0,sizeof(cntl));
memset(cntr,0,sizeof(cntr));
int mn=a[l],Lpos=l-1;
cntl[a[l-1]]++;
for(int i=l-2;i>=1;i--){
if(a[i]>=a[i+1]){
Lpos=i;
cntl[a[i]]++;
}else break;
}
cntr[a[l]]++;
int ptr=0;
int cntmn=0,len=0,mx=0;
if(a[l]<a[l-1]){
mn=a[l];
cntmn++;
}
for(int r=l+1;r<=n;r++){
mx=max(mx,a[r]);
cntr[a[r]]++;
if(a[r]<=ptr&&a[r]!=mn){
while(ptr>=a[r]){
if(ptr!=mn){
len-=cntl[ptr];
}
ptr--;
}
}
if(a[r]<mn&&mn<a[l-1]){
break;
}
mn=min(mn,a[r]);
if(mn>=a[l-1]) continue;
if(a[r]==mn) cntmn++;
while(ptr<=V&&(cntl[ptr+1]==cntr[ptr+1]||ptr+1==mn)){
if(ptr+1!=mn) len+=cntl[ptr+1];
ptr++;
}
if(len==l-1-Lpos+1&&r-l+1-cntmn==l-1-Lpos+1) ans=max(ans,r-Lpos+1+2*lcp[Lpos-1][r+1]);
else{
ans=max(ans,2*len+cntmn+2*min(cntl[ptr+1],cntr[ptr+1]));
}
}
}
void work(){
for(int i=1;i<=n;i++){
for(int j=n;j>=1;j--){
if(a[i]==a[j]) lcp[i][j]=1+lcp[i-1][j+1];
else lcp[i][j]=0;
}
}
for(int i=1;i<=n;i++){
ans=max(ans,lcp[i][i]*2-1);
ans=max(ans,lcp[i][i+1]*2);
}
if(ans==n){
cout<<ans<<"\n";
exit(0);
}
for(int i=1;i<=n;i++){
int l=lcp[i][i];
solve1(i-l,i+l);
l=lcp[i][i+1];
solve1(i-l,i+1+l);
}
for(int l=2;l<=n;l++){
solve2(l);
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>V;
for(int i=1;i<=n;i++){
cin>>a[i];
cnt[a[i]]++;
}
for(int i=1;i<=V;i++) ans=max(ans,cnt[i]);
work();
reverse(a+1,a+1+n);
for(int i=1;i<=n;i++) a[i]=V-a[i]+1;
work();
cout<<ans<<"\n";
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...