[题解]CF1774C Ice and Fire
题意简述
有\(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;
}