22河南省赛 - E. Serval 的俳句(预处理)

https://codeforces.com/gym/103941

题意
给定长度为 n 的包含小写英文字母的字符串 S,需要找到长度为 17 的满足下面条件的一个子序列:

  • 前 5 个字符相同,中间 7 个字符相同,最后 5 个字符相同。

输出一个满足的子序列。不存在输出 -1。

1 ≤ ∣ S ∣ ≤ 1 0 6 1 ≤ |S| ≤ 10^6 1S106

思路
这题的思路来源于前几天模拟的一场 22上海市赛 - E. Expenditure Reduction(预处理),预处理出来 每个位置后面,每个字符首次出现的位置 ne[i, j]

首先遍历第一种字符,然后找到最前面的 5 个,然后遍历第二种字符,找到最前面的 7 个,然后遍历第三种字符,找到最前面的 5 个。三重循环。
每次都贪心找最前面满足的,给后面的字符尽量留更多的位置。

还有一种思路是,边走边记录每个字符出现的次数,如果有一个字符出现 5 次了,那么就满足了,清空次数重新记录,然后找首个出现 7 次的字符作为第二种 …
这样每次找到的也是最前面满足的,满足贪心。

#include<bits/stdc++.h>
using namespace std;

const int N = 1000010;
int n, m;
char a[N];
int ne[N][30];

int main(){
	cin >> n;
	cin >> a + 1;
	
	for(int i=n-1;i>=0;i--)
	{
		for(int j=1;j<=26;j++) ne[i][j] = ne[i+1][j];
		ne[i][a[i+1]-'a'+1] = i+1;
	}
	
	for(int i=1;i<=26;i++)
	{
		int now1 = ne[0][i];
		if(!now1) continue;
		int cnt = 1;
		while(cnt < 5 && ne[now1][i]) now1 = ne[now1][i], cnt ++;
		if(cnt != 5) continue;
		
		for(int j=1;j<=26;j++)
		{
			int now2 = ne[now1][j];
			if(!now2) continue;
			cnt = 1;
			while(cnt < 7 && ne[now2][j]) now2 = ne[now2][j], cnt ++;
			if(cnt != 7) continue;
			
			for(int k=1;k<=26;k++)
			{
				int now3 = ne[now2][k];
				if(!now3) continue;
				cnt = 1;
				while(cnt < 5 && ne[now3][k]) now3 = ne[now3][k], cnt ++;
				if(cnt != 5) continue;
				
				for(int t=1;t<=5;t++) cout << char('a' + i - 1);
				for(int t=1;t<=7;t++) cout << char('a' + j - 1);
				for(int t=1;t<=5;t++) cout << char('a' + k - 1);
				return 0;
			}
		}
	}
	
	cout << "none";
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值