Codeforces Round 721 Div2

本文介绍了两场比赛的解题思路:AndThenThereWereK中利用二进制计数判断,PalindromeGame中分析女生的必胜策略。详细解析了回文游戏中0的分布对游戏结果的影响,以及如何通过巧妙操作确保Alice的胜利。
摘要由CSDN通过智能技术生成

比赛链接

A.And Then There Were K

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
int main() {
	int t;
	cin >> t;
	while (t--) {
		ll a;
		cin >> a;
		int cnt = 0;
		while (1) {
			if (a >> 1)cnt++;
			else break;
			a >>= 1;
		}
		cout << (int)pow(2, cnt) - 1 << '\n';
	}
}

B.Palindrome Game (easy version)

如题所示,有两种操作

  1. 花一块钱 将一个0改成1
  2. 不花钱 翻转

思路:

因为给的是回文,所以第一步女生必然花一块钱。

首先我们记录0的个数为cnt
那么:

  • cnt==0,显然“DRAW”
  • cnt==1,显然是“BOB”
  • 以上是俩特判
  • cnt%2==0,也就是有偶数多个0,由于是回文,所以0的位置是对称的,那么女生花一块钱之后,男生也可以在女生操作的对称位置花一块钱,直到剩下一个0,那这时候男生选择翻转,女生就又得花一块钱了,也就是说这种情况男生必胜。
  • 剩下的都是女生的必胜局,为什么呢?因为如果有奇数多个0,代表回文长度也是奇数,而且正中间必然是0,那女生可以把正中间的0改成1,接下来就与上面同理了,只是因为这样算是男生先手,所以女生必胜。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=1e3+7;
int a[N];
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		int cnt=0;
		for(int i=1;i<=n;i++){
			scanf("%1d",&a[i]);
			if(a[i]==0)cnt++;
		}
		if(cnt>0&&cnt%2==0){
			cout<<"BOB"<<'\n';continue;
		}
		if(cnt==0){
			cout<<"DRAW"<<'\n';continue;
		}
		if(cnt==1){
			cout<<"BOB"<<'\n';continue;
		}
		cout<<"ALICE"<<'\n';
	}
}

看榜时发现这题居然卡了众多大佬,有点吃惊。

C. Sequence Pair Weight

暴力枚举不可取,所以要想新思路

假设数组下标从1开始:

设最终答案为res。

每当遇到一对值相等的元素,记录其下标为i和j,那么它对res的贡献是i*(n-j+1)

下面我解释一下这个公式:
	i向左有i个数,j向右有(n-j+1)个数(包括本身)。
	
	假设i==3,j==5,那么区间[3,5]算一次答案,区间[2,5]也算一次答案
	区间[3,6]也算一次答案....等等等等,总的来说就是一共有i(n-j+1)个区间包
	含了区间[i,j]。
	
接下来很容易想到一种方法:
	for(int i=1;i<=n;i++){
	   for(int j=i+1;j<=n;j++){
	      if(a[i]==a[j]){
	         res=res+i*(n-j+1)
	      }
	   }
	}
但是很遗憾,这种方法会超时,所以这时候可以用map来提高效率
	以样例1 2 1 1为例子(**假设数组下标从1开始**)
	现在对于a[4]来说,a[1]和a[3]都是符合条件的,那么
	res=res+1*(4-4+1)+3*(4-4+1)
	上面那条式子可以写成res+=(1+3)*(4-4+1)
	那么下面的AC代码就呼之欲出了(没看懂的话请直接看代码)
	
	#include <iostream>
	#include <cstdio>
	#include <algorithm>
	#include <cstring>
	#include <map>
	using namespace std;
	typedef long long ll;
	int main(){
		int t;
		cin>>t;
		while(t--){
			map<int,ll>a;
			ll res=0;
			int n;cin>>n;
			for(int i=1;i<=n;i++){
				int x;cin>>x;
				res+=a[x]*(n-i+1);
				a[x]+=i;
			}
			cout<<res<<'\n';
		}
	}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值