题意很简单,我一开始的思路是填两个相同字母之间的缝隙:
预处理每个字母出现的位置,然后在线处理询问,从左到右枚举起点,用可以填补的字母填补缝隙,维护最长长度。加上各种优化以后复杂度O(NQ),但可能卡了常数,虽然初测花样AC,但最终还是倒在了某一组极限数据上。
(当晚终测前czy623和S10问我解题思路时我还非常自信地认为是能够卡过的,因为BNU的Q神也是这个复杂度,结果… 果然还是太弱了,写的丑陋代码被卡了常数)
那天晚上打完比赛脑海里一直在构思优化方案,后来洗澡时忽然灵光一现,N=1500,如果用O(26N2)的复杂度先将每两个字母的缝隙预处理出来,然后对于询问在线二分,这个复杂度大概O(26*N2 + QLogN)两秒的时限是一定能过的。
但因为自己写的二分太丑了,还是改了很久才过掉。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int A = 2e3 + 10;
int a[30][A];
int cnt[A];
vector<int> V[30];
char s[A];
int bi_search(int id,int val){
int l = 0,r = V[id].size() - 1;
if(val >= V[id][r]) return r;
while(l <= r){
int mid = (l+r)>>1;
if(V[id][mid] > val){
r = mid - 1;
}
else{
l = mid + 1;
}
}
l = (l+r)>>1;
while(val < V[id][l]) l--;
while(val >=V[id][l+1]) l++;
return l;
}
int main(){
//freopen("input","r",stdin);
int n;
scanf("%d",&n);
scanf("%s",s);
for(int i=0 ;i<n ;i++){
int id = s[i] - 'a';
int num = cnt[id];
cnt[id]++;
a[id][num] = i;
}
for(int i=0 ;i<26 ;i++){
int now = 0;
V[i].push_back(now);
for(int j=0 ;j<cnt[i]-1 ;j++){
now += (a[i][j+1] - a[i][j] - 1);
V[i].push_back(now);
}
for(int j=1 ;j<cnt[i]-1 ;j++){
now = 0;
for(int k=j ;k<cnt[i]-1 ;k++){
now += (a[i][k+1] - a[i][k] - 1);
V[i][k-j+1] = min(V[i][k-j+1],now);
}
}
}
int q;
scanf("%d",&q);
char str[5];
for(int i=1 ;i<=q ;i++){
int all;
scanf("%d%s",&all,str);
int id = str[0] - 'a';
if(cnt[id] <= 1){
printf("%d\n",min(n,all+cnt[id]));
continue;
}
if(all >= n){
printf("%d\n",n);
continue;
}
int pos = bi_search(id,all);
printf("%d\n",min(n,pos+all+1));
}
return 0;
}
然后官方题解是枚举区间,通过区间长度 - 区间某字母的重复个数得到需要填补的字母个数,通过维护最优解来预处理,最后以O(1)的复杂度查询。
我自己也写了一下,跑的情况来看:
官方题解:140ms
我自己的方法:124ms
代码:(官方题解提供的思路)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int A = 2e3 + 10;
int Ans[30][A];
char s[A];
int main(){
int n;
scanf("%d",&n);
scanf("%s",s);
for(int id=0; id<26;id++){
for(int i=0 ;i<n ;i++){
int now = 0;
for(int j=i ;j<n ;j++){
if(s[j] != 'a'+id) now++;
Ans[id][now] = max(Ans[id][now],j-i+1);
}
}
for(int i=1 ;i<A ;i++){
Ans[id][i] = max(Ans[id][i],Ans[id][i-1]);
}
}
int q;
scanf("%d",&q);
char str[5];
while(q--){
int all;
scanf("%d%s",&all,str);
printf("%d\n",Ans[str[0]-'a'][all]);
}
return 0;
}