[题解]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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效