[题解]CF1774C Ice and Fire

CF1774C Ice and Fire *1300

Luogu

题意简述

\(n\)个人,第\(i\)个人温度为\(i\),进行\(n-1\)次对战。

所以给出一个长度为\(n-1\)\(01\)\(s\)\(s_i\)表示第\(i\)局的对战环境为\(0\)\(1\)

每局任意选出\(2\)人对战,规则如下:

  • 如果该局对战环境为\(0\),则两人中温度低的获胜。
  • 如果该局对战环境为\(1\),则两人中温度高的获胜。
  • 每局结束,失败者被淘汰,其他玩家继续对战。

给定\(T\)组测试样例,每组样例给出\(n\)和长度为\(n\)\(s\)

对于每组样例,请分别输出前\(2\)个人、前\(3\)个人、……、前\(n\)个人按\(s\)的规则进行对局(\(s\)可能有剩余),多少人有机会获胜。

思路分析

咱先管前\(n\)个对局的情况。

首先可以发现当\(s\)全为\(0\)时,答案就是\(1\),而\(s\)全为\(1\)时,答案就是\(n\)

那么当\(s\)\(000111\)这种有两段的,怎么办?

\(s\)为两段的分析

\(n=6,s=00011\)时,我们发现填完前面\(3\)\(0\)时,答案就是剩下的最大值了。所以我们只需要考虑前三轮对局剩下玩家的最大温度是多少。

我们设最后一段的长度为\(k=2\)

我们可以发现如果某次对局环境是\(0\),那么我们能淘汰掉的值在\([2,n]\)区间内;如果是\(1\)则在\([1,n-1]\)内。

于是在这个样例中,前\(3\)次对战就相当于在\([2,6]\)中选取\(n-k-1=3\)个值淘汰掉,剩下\(3\)个。

  • 如果淘汰掉的人正好是\(\{6,5,4\}\),那么最大值就是\(3\)了。
  • 如果淘汰掉的人是\(\{6,5,3\}\)\(\{6,5,2\}\)等,那么最大值就是\(4\)了。
  • 如果淘汰掉的人是\(\{6,4,3\}\)等,那么最大值就是\(5\)了。
  • 如果淘汰掉的人是\(\{5,4,3\}\)等,那最大值不变,就是\(6\)

综上我们可以发现,\(s\)为两段时,根据被淘汰的人的连续情况,剩下人的最大值在\([k+1,n]\)之间,故答案为\(n-k\)

推广——\(s\)为多段的分析

\(s\)\(3\)段或以上,会怎样呢?

\(n=7,s=100011\)时,\(k=2\),同样是求对战\(4\)次后的最大值。

那么前\(4\)次对战,我们相当于在\([1,n-1]\)淘汰掉\(1\)个,再在\([2,n]\)淘汰掉\(3\)个。

于是前\(4\)次对战就相当于在\([1,n]\)中选取\(n-k-1=4\)个值淘汰掉,剩下\(3\)个。

是不是很眼熟?只不过这次的区间是\([1,n]\),但是显然这并没有影响。因为对战一共\(n-1\)局,所以在最后一段前最多进行\(n-2\)次比赛。最坏情况我们可选淘汰的区间长度为\(n-1\),这种情况刚好够组成\(n-k\)个最大值,更别说这种可选区间长度为\(n\)的情况了。

所以呢,答案还是\(n-k\)

预处理

至此,求前\(x\)个的答案,就是看\(s\)的前\([1,x]\)中,最后一段的长度。

直接遍历求每一个会超时,所以我们可以用\(dp\)的思想预处理一下。

实现见代码吧。

Code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int t,n,siz[200010];
string s;
int main(){
	cin>>t;
	while(t--){
		cin>>n>>s;
		int len=s.size();
		siz[0]=1;
		for(int i=1;i<len;i++){
			if(s[i]==s[i-1]) siz[i]=siz[i-1]+1;
			else siz[i]=1;
		}
		for(int i=2;i<=n;i++){
			cout<<i-siz[i-2]<<" ";
		}
		cout<<endl;
	}
	return 0;
}
posted @ 2024-03-21 22:48  Sinktank  阅读(9)  评论(0编辑  收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2024 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.