10月28日NOIP2018提高组省一冲奖班模测训练4
T2 奇怪的回文串
题目描述
小D对字符串有着奇怪的认识。对于一个字符串S,他认为S是满足“奇数-回文”性质,当且仅当这个串的所有长度为奇数的子串都是回文串。注意一个串的子串指的是串中任意连续位置形成的串,一个“奇数-回文”串本身并不需要长度为奇数。
现在小D有一个长度为N的字符串S。他有K次修改这个字符串的机会。每次修改,他可以选择字符串上的任意一个位置,把这个位置修改成任意一种字符。他希望使得修改后的串中满足“奇数-回文”性质的子串的长度最大。注意K次机会不必用完。
输入格式
第一行包含两个整数K,N。 接下来一行N个整数,第i个整数代表字符串S第i位的字符。
输出格式
输出一个整数,表示最大可能的满足“奇数-回文”性质的子串长度。
输入样例
1 6
1 2 3 4 5 6
输出样例
3
数据范围
对于20%的数据,N≤10 对于40%的数据,N≤100 对于60%的数据,N≤5000 对于100%的数据,1≤K≤N≤500000,保证给定的字符串的字符为1到10^9间的整数。
思路
堆优化
20pts
暴力, 没有什么技术含量,故不多赘述
60pts
找规律
稍加分析,我们可以发现,如果要满足“奇数-回文”性质,那么这一段子串的奇数位和偶数位的字符是相同的,枚举子串,记这一段子串[l, r], 其中奇数位出现次数最多为odd, 偶数位为even, 则修改的次数为.
100pts
堆优化
固定左端点,每次右端点在次数小于k的情况下尽量拓展,用序列长度更新答案
然后左端点加加,重复上个过程
在其中写两个支持删除操作的堆,维护奇数位置和偶数位置中同一个字符最多有多少个
代码(60pts)
//fx 60pts
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 5e5 + 5;
int K, n, nn, maxo, maxe, cnt, ans;
int a[MAXN], d[MAXN], odd[MAXN], even[MAXN];
inline int read ();
int main ()
{
K = read (), n = read ();
for (int i = 1; i <= n; ++ i){
a[i] = read ();
d[i] = a[i];
}
sort (d + 1, d + 1 + n);
nn = unique (d + 1, d + 1 + n) - d;
for (int i = 1; i <= n; ++ i){
a[i] = lower_bound(d + 1, d + 1 + nn, a[i]) - d + 1;
}
for (int i = 1; i <= n; ++ i){
memset (even, 0, sizeof (even));
memset (odd, 0, sizeof (odd));
maxo = 0;
maxe = 0;
for (int j = i; j <= n; ++ j){
if (j % 2 == 0){
++ odd[a[j]];
maxo = max (maxo, odd[a[j]]);
}
else {
++ even[a[j]];
maxe = max (maxe, even[a[j]]);
}
cnt = j - i + 1 - maxo - maxe;
if (cnt <= K) ans = max (ans, j - i + 1);
}
}
printf ("%d", ans);
return 0;
}
inline int read ()
{
char ch = getchar ();
while (!isdigit (ch)) ch = getchar ();
int x = 0;
while (isdigit (ch)){
x = x * 10 + ch - '0';
ch = getchar ();
}
return x;
}
代码(100pts)
#include <iostream>
#include <cstdio>
#include <cctype>
#include <queue>
#include <map>
using namespace std;
const int MAXN = 5e5 + 5;
int n, k, l, r, ans;
int a[MAXN];
struct Node
{
int ch, ct;
bool operator < (const Node &rhs) const
{
return ct < rhs.ct;
}
};
priority_queue <Node> Q[2];
map<int, int> cnt[2];
inline int read ();
int main()
{
freopen ("solo.in", "r", stdin);
freopen ("solo.out", "w", stdout);
k = read (), n = read ();
for (int i = 1; i <= n; ++i){
a[i] = read ();
}
l = 1;
r = 1;
ans = 0;
for (int i = 1; i <= n; ++i){
while(r <= n){
if(r & 1) {
Q[1].push (Node{a[r], ++cnt[1][a[r++]]});
}
else{
Q[0].push (Node{a[r], ++cnt[0][a[r++]]});
}
Node tmp1, tmp0;
while (! Q[1].empty()){
tmp1 = Q[1].top();
if (cnt[1][tmp1.ch] == tmp1.ct) break;
Q[1].pop();
}
while (! Q[0].empty()){
tmp0 = Q[0].top();
if (cnt[0][tmp0.ch] == tmp0.ct) break;
Q[0].pop();
}
if(r - l - tmp1.ct - tmp0.ct> k) break;
ans = max (ans, r - l);
}
if(l & 1) {
Q[1].push (Node{a[l], --cnt[1][a[l++]]});
}
else{
Q[0].push (Node{a[l], --cnt[0][a[l++]]});
}
}
printf("%d\n", ans);
fclose (stdin);
fclose (stdout);
return 0;
}
inline int read ()
{
char ch = getchar ();
while (!isdigit (ch)) ch = getchar ();
int x = 0;
while (isdigit (ch)){
x = x * 10 + ch - '0';
ch = getchar ();
}
return x;
}