Codeforces Round #721 (Div. 2)

Codeforces Round #721 (Div. 2)

A. And Then There Were K

在这里插入图片描述

Example

input

3
2
5
17

output

1
3
15

题目大意:

给一个正整数n,求最大的k,使得 n & (n−1) & (n−2) & (n−3) & … (k) = 0

思路:

就假设n为17,二进制为10001,我们来模拟一下求解过程。

17 10001

16 10000

15 01111

因为按位与的特点就是,一位上只要有一个0,这一位最后就是0。

我们竖着来看,17到15,每一位上就都出现过一次0了,所以15就是答案。然后举更多例子观察特点,发现,答案就是让n的二进制最左边的1置为0,后面全置为1。

如:

10001 11101 10111的答案都是01111

代码:

#include<algorithm>
#include<iostream>
#define endl '\n'
#define int long long
using namespace std;
int qpow(int a,int b){int ans=1;while(b){if(b&1)ans=ans*a;b>>=1;a=a*a;}return ans;}

signed main()
{
	int n;
	cin>>n;
	while(n--)
	{
		int a;
		cin>>a;
		int ans=0;
		while(a)//有多少位
		{
			a>>=1;
			++ans;
		}
		--ans;
		cout<<qpow(2,ans)-1<<endl;
	}
	return 0;
}

遇到这种位运算的题目,一般都是把数的二进制表示出来,然后根据运算的特点(比如&的特点就是,只要有一个0,最后就是0),找规律。

B1. Palindrome Game (easy version)

在这里插入图片描述

Example

input

2
4
1001
1
0

output

BOB
BOB

在这里插入图片描述

题目大意:

给一个字符串(这题的字符串一开始一定是一个回文)。

1.可以把一个0变为1,操作者的数字+1。

2.或者翻转整个字符串(前提是该字符串不是回文且上一个人的操作不是翻转)。

Alice先,最后字符串全为1时,谁的数字大谁输,相同则平局。

思路:
因为一开始就是回文,所以Alice只好进行1操作,如果可以在这个操作之后仍然让它时一个回文,那Alice就赢定了。

比如:10001

Alice进行1之后,10101

Bob没法翻转,只好进行1操作,11101

这时,Alice很聪明,不会傻傻地让自己的数字变大,选择2翻转字符串,10111

Bob只好继续1操作,111111

这时Bob都已经数字为2了,Alice为1,所以Alice胜

比如:10101

Alice 1操作之后并不是回文,这就让Bob有机可乘,最后是Bob赢了

关键在于,Alice第一次操作之后它还是不是回文,而这取决于改字符串中间的字符是不是0,只有中间的字符是0,且字符串长为奇数(偶数的话连中间都没有)的时候Alice赢,否则Bob赢。

还有一个特殊情况,就是只有一个0的时候,因为刚开始就是回文,Alice只好1操作,所以Alice必定+1,而Bob是0,所以Bob赢了。

代码:

#include<algorithm>
#include<iostream>
#include<string>
#define endl '\n'
#define int long long
using namespace std;

signed main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		string a;
		cin>>a;
		int numzero=0;
		for(int i=0;i<a.size();++i)
		{
			if(a[i]=='0')
			{
				++numzero;
			}
		}
		if(numzero==1)cout<<"BOB"<<endl;//只有一个0
		else if((n&1)&&a[n/2]=='0')//是奇数个,中间为0
		{
			cout<<"ALICE"<<endl;
		}
		else
		{
			cout<<"BOB"<<endl;
		}
	}
	return 0;
}

博弈题,自己模拟题意,试着发现一些规律吧,这题没有平局的情况,结果我当时一直不敢提交。。

B2. Palindrome Game (hard version)

同B1

Example

input

3
3
110
2
00
4
1010

output

ALICE
BOB
ALICE

在这里插入图片描述

题目大意:

这题跟B1的区别就是,一开始的字符串可能不是回文。

思路:

一开始是回文时,用B1的结论。

一开始不是回文时,Alice就可以一开始就翻转,让Bob喘不过气来,所以Bob不可能赢。

但是有一种平局的情况,001,只有2个0,且中间是0。

代码:

#include<algorithm>
#include<iostream>
#include<string>
#define endl '\n'
#define int long long
using namespace std;

signed main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		string a;
		cin>>a;
		string b=a;
		reverse(b.begin(),b.end());
		int numzero=0;
		for(int i=0;i<a.size();++i)
		{
			if(a[i]=='0')
			{
				++numzero;
			}
		}
		if(b==a)//用1的结论
		{
			if(numzero==1||!(n&1))cout<<"BOB"<<endl;
			else if((n&1)&&a[n/2]=='0')
			{
				cout<<"ALICE"<<endl;
			}
			else
			{
				cout<<"BOB"<<endl;
			}
		}
		else
		{
			if(numzero==2&&(n&1)&&a[n/2]=='0')cout<<"DRAW"<<endl;//只有这一种情况平局
			else cout<<"ALICE"<<endl;
		}
	}
	return 0;
}

C. Sequence Pair Weight

在这里插入图片描述

Example

input

2
4
1 2 1 1
4
1 2 3 4

output

6
0

题目大意:

给一个数组,求每个子序列的一对相同数字的数量之和。

分析:

暴力O(n*n),肯定不行,所以肯定有什么O(n)的方法可以实现。

首先,答案肯定跟这些数字出现的次数有关,其次,也跟数字所在的位置有关。

代码:

#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#define endl '\n'
#define int long long
using namespace std;

map<int,int>ma;

signed main()
{
	fastio();
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		int ans=0;
		for(int i=1;i<=n;++i)
		{
			int a;
			cin>>a;
			ans+=ma[a]*(n-i+1);
			ma[a]+=i;
		}
		cout<<ans<<endl;
		ma.clear();
	}
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值