NOIP2018提高组省一冲奖班模测训练4 T2 奇怪的回文串

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, 则修改的次数为r - l - 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;
 } 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值