【JOI 2020 Final】【LOJ3253】JJOOII(队列)

传送门


题解:

用队列算一下每个位置向后找到哪里有 k k k 个指定字符,然后枚举开头 O ( 1 ) O(1) O(1) 跳到结尾即可算出中间要删掉多少。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

cs int N=2e5+7;

int n,K;
char s[N];
int nxJ[N],nxO[N],nxI[N];

void get(int nx[],char c){
	std::queue<int>q;int l=0;
	for(int re i=1;i<=n;++i)
		if(s[i]==c){
			q.push(i);
			if(q.size()==K){
				for(int re j=l+1;j<=q.front();++j)
					nx[j]=i;
				l=q.front();q.pop();
			}
		}
	for(int re i=l+1;i<=n;++i)nx[i]=1e9;
}

void Main(){
	scanf("%d%d%s",&n,&K,s+1);int ans=1e9;
	get(nxJ,'J'),get(nxO,'O');get(nxI,'I');
	for(int re i=1;i<=n;++i){
		int j=nxJ[i];if(j>=n)continue;
		j=nxO[j+1];if(j>=n)continue;
		j=nxI[j+1];if(j>n)continue;
		ans=std::min(ans,j-i+1-K*3);
	}cout<<(ans==1e9?-1:ans)<<"\n";
}

inline void file(){
#ifdef zxyoi
	freopen("JJOOII.in","r",stdin);
#endif
}
signed main(){file();Main();}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值