首页 > 其他分享 >乒乓球题解()

乒乓球题解()

时间:2024-10-25 15:13:36浏览次数:6  
标签:11 last ++ 题解 len 乒乓球 int &&

30pts

考场上看到这个题时,第一反应就是全部展开man慢算

诶,刚好有30分部分分可以 \(O(n)\) 维护

那么使用 \(tot\) 来记录遍历到哪一位了,当 \(tot\) 遍历到结尾时直接让他归0即可

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,len,tot,a,b,A,B;
char t[100100];
int main(){
	cin>>n>>len>>t+1;
	for(int i=1;i<=n;i++){
		if(tot==len){
			tot=0;
		}
		if(t[++tot]=='A'){
			a++;
		}
		else{
			b++;
		}
		if(a>=11&&a-b>=2){
			A++;
			a=b=0;
		}
		if(b>=11&&b-a>=2){
			B++;
			a=b=0;
		}
	}
	cout<<A<<":"<<B<<endl;
}

50pts

发现如果某一次遍历完整个串之后恰好打完了一局,那么显然是一个循环节,于是可以每次结束时判断如果此时小红和 zwh 的得分都被清空了,就跳出循环。

有注意到3点:

  1. if 会增加时间复杂度
  2. 我们一个循环节的长度无法表示
  3. 不知道一个循环节的得分情况

对应的解决:

  1. 特判 \(n≤1e7\) 的情况
  2. 记录 \(last\) 表示跳出循环时的 \(i\) ,那么循环节的长度就是 \(last\) 了
  3. 记录 \(mapp[i]\) 和 \(mbpp[i]\) 分别表示 zwh 和 小红的得分情况
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,len,tot,flag=1,fff,a,ff,zxc=1e9,b,cnt1,cnt2,A,B,last;
map<int,int> mapp,mbpp;
char t[200100];
signed main(){
	cin>>n>>len>>t+1;
	if(n<7e7){
		for(int i=1;i<=n;i++){
			if(tot==len){
				tot=0;
			}
			if(t[++tot]=='A'){
				a++;
			}
			else{
				b++;
			}
			if(a>=11&&a-b>=2){
				A++;
				a=b=0;
			}
			if(b>=11&&b-a>=2){
				B++;
				a=b=0;
			}
		}
		cout<<A<<":"<<B<<endl;
		return 0;
	}
	for(int i=1;i<=n;i++){
		if(tot==len){
			if(A==0&&B==0&&flag&&a==b){
				cout<<"0:0";
				return 0;
			}
			if(fff){
				break;
			} 
			if(a==0&&b==0){
				fff=1;
				break;
			}
			tot=0;
		}
		if(t[++tot]=='A'){
			a++;cnt1++;
		}
		else{
			b++;cnt2++;
		}
		if(a>=11&&a-b>=2){
			A++;
			a=b=0;
		}
		if(b>=11&&b-a>=2){
			B++;
			a=b=0;
		}
		if(abs(a-b)>=2){
			flag=0;
		}
		mapp[i]=A;
		mbpp[i]=B;
		last=i;
	}
	if(!fff){
		cout<<mapp[n]<<":"<<mbpp[n]<<endl;
		return 0;
	}
	int ans=n/last*A+mapp[n%last],bns=n/last*B+mbpp[n%last];
	cout<<ans<<":"<<bns<<endl;
}

100pts

叕发现当之前遍历完字符串之后和目前 zwh 和 小红 的得分一样,那么就也是一个循环节

以样例2为例(左侧zwh):

以 \(len\) 为周期比分变化为:

3 3

6 6

9 9

1 3

4 6

7 9

1 1

4 4

7 7

10 10

1 3

4 6

7 9

1 1

4 4

7 7

10 10

。。。

那么,只需要去除前3次遍历,就是一个完美的循环了!

最后剩余的部分也在循环里,所以可以直接求出!

时间复杂度:\(O(能过就行了应该是不大于1000的常数乘k吧)\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,len,tot,flag=1,fff,a,ff,zxc=1e9,b,cnt1,cnt2,A,B,last,mapp[3000100],mbpp[3000100];
char t[200100];
map<int,map<int,int> >ma;
signed main(){
	cin>>n>>len>>t+1;
	ma[0][0]=1;
	for(int i=1;i<=n;i++){
		if(tot==len){
			if(A==0&&B==0&&flag&&a==b){
				cout<<"0:0";//特判ABABABABABABABABABABABAB……的情况 
				return 0;
			}
			if(a==0&&b==0){
				fff=1;
				break;
			}
			if(ma[a][b]){
				ff=ma[a][b];//记录循环的开始 
				zxc=i-ff-1;//记录循环节长度 
				fff=1;
				break;
			}
			ma[a][b]=i-1;
			tot=0;
		}
		if(t[++tot]=='A'){
			a++;cnt1++;
		}
		else{
			b++;cnt2++;
		}
		if(a>=11&&a-b>=2){
			A++;
			a=b=0;
		}
		if(b>=11&&b-a>=2){
			B++;
			a=b=0;
		}
		if(abs(a-b)>=2){
			flag=0;
		}
		mapp[i]=A;
		mbpp[i]=B;
		last=i;
	}
	if(!fff){//当n特别小时 
		cout<<mapp[n]<<":"<<mbpp[n]<<endl;
		return 0;
	}
	if(!ff){//当n比较小时 
		int ans=n/last*A+mapp[n%last],bns=n/last*B+mbpp[n%last];
		cout<<ans<<":"<<bns<<endl;
	}
	else{
		//重点!接下来两行相当难,建议自己思考懂,我只解释一点 
	
	
	
		// 解释:n-ff 是除去非循环部分,A-mapp[ff]同理
		// mapp[ff+(n-ff)%zxc]-mapp[ff]是计算剩余部分 
		int ans=mapp[ff]+(n-ff)/(zxc)*(A-mapp[ff])+mapp[ff+(n-ff)%zxc]-mapp[ff];
		int bns=mbpp[ff]+(n-ff)/(zxc)*(B-mbpp[ff])+mbpp[ff+(n-ff)%zxc]-mbpp[ff];
		cout<<ans<<":"<<bns<<endl;
	}
}
<details> <summary>点击查看代码</summary>

</details>

标签:11,last,++,题解,len,乒乓球,int,&&
From: https://www.cnblogs.com/lewisak/p/18502583

相关文章

  • ♿交换序列题解♿
    以下将状态\(K\),\(E\),\(Y\)用数字0,1,2表示。考虑\(dp\)我们设\(dp[a][b][c][d]\)表示\(K\)用了\(a\)次,\(E\)用了\(b\)次,\(Y\)用了\(c\)次,总共交换了\(d\)次,前缀和$sum[i][j]$表示到第\(j\)位有几个字母\(i\)记录一个\(loc[i][j]\)表示第\(j\)个字......
  • 序列题解
    哈哈哈我也有个唐氏做法也是考虑一个朴素dp,设\(dp_{i}\)表示以\(i\)结尾的字串最长是多少,则容易想到若\(a_{i-1}\)和\(a_i\)是等比数列的一部分就一定能从\(dp_{i-1}\)转移到\(dp_i\),证明最后讲那么如何判断\(a_{i-1}\)和\(a_i\)是否为等比数列的一部分呢?首先......
  • 最长的Y题解
    考虑将Y单独拎出来,用数组存储他的下标,那么将第\(x\)个Y转移至第\(y\)个Y就需要\(a[x]-b[y]-1\)次操作。发现一个问题:第一次从左移动至\(y\)需要减1,第二次从左移动需要减2……如图:这似乎是一个很麻烦的问题,我们的某知名\(lyh\)教授是通过指针(应该是吧)解决的。......
  • 家谱树题解
    (ACM比赛时忘了拓扑怎么写时代尻古)假设有一个DAG图,那么如何写出它的拓扑排序呢?这里说一种比较常用的方法:1.从DAG图中选择一个没有前驱(即入度为0)的顶点并输出。2.从图中删除该顶点和所有以它为起点的有向边。3.重复1和2直到当前的DAG图为空或当前图中不存在无前驱的......
  • SSL证书常见问题解答
    在当今的数字时代,确保网站和数据的安全性变得尤为重要。SSL(SecureSocketsLayer)证书作为保障网站安全的关键组件,广泛应用于各种在线服务中。然而,在SSL证书的申请、安装和使用过程中,用户常常会遇到各种问题。本文旨在提供一个全面的指南,帮助用户理解并解决SSL证书的常见问题。......
  • 题解:CF722D Generating Sets
    涉及知识点:set。解题思路每次让列表中最大的元素缩小两倍,保证答案最优。如果当前的元素缩小成$0$就直接跳出循环,输出这个序列。由于序列需要支持插入、删除以及找最大值,所以这个序列可以用set来维护。代码#include<bits/stdc++.h>#defineintlonglong#definell......
  • 题解:P10298 [CCC 2024 S4] Painting Roads
    涉及知识点:图的遍历。我们观察样例可以发现,染色之后的图是一颗树,而且还是dfs树。题目要求所以路径上的颜色都是交替的,所以直接交替染色即可。注意:建图的时候需要记录当前边的编号。代码#include<bits/stdc++.h>#defineintlonglong#definell__int128#definedbd......
  • 题解:SP25334 NPC2015A - Eefun Guessing Words
    涉及知识点:字符串处理。解题思路记录每个字符出现的第$1$个位置和最后$1$个位置,询问时比较大小即可。代码#include<bits/stdc++.h>//#defineintlonglong#definell__int128#definedbdouble#defineldblongdouble#definevovoid#defineendl'\n'#defin......
  • 题解:CF1988B Make Majority
    题目大意题面写得很清楚,我就不再赘述了。解题思路涉及知识点:字符串,构造。由于所有相邻的$0$合并完会变成一个$0$,所以先贪心地把所有挨在一起的$0$合并起来,放在一个新的字符串里。而且题目需要你判断是否最终是否能合并成一个$1$,所以$1$是不需要想$0$一样合并的,这......
  • 题解:CF1994B Fun Game
    涉及知识点:异或,字符串处理。解题思路‌异或是一种二进制运算,用于比较两个数字的差异。当两个输入不同时,异或运算的结果为1;当两个输入相同时,结果为0。现在就可以切掉本题了。设两个字符串分别为$a$,$b$。如果$a$和$b$完全相同,输出Yes。如果$a$中没有$1$且$b$......