Codeforces思维题训练

10 篇文章 0 订阅

1.1547D. Co-growing Sequence(思维+位运算)

原题链接:Problem - 1547D - Codeforces

思路学习来源:CF1547D Co-growing Sequence(位运算,思维)_x-d-xxh的博客-CSDN博客

题意:
长度为n的序列a,找到一个字典序最小的序列b,使ai xor bi后满足ai and ai+1 == ai
思路:
a xor 0 == a
a xor b == a+b(同1会变为0)
为了字典序最小,b1肯定是0
ai-1 and ai == ai-1
(与ai and ai+1 == ai同理)
(假设ai-1=10011,ai=10100)
1.找出所有有1的位置
or 10011
    10100
=  10111
2.减去ai上原本有的1(ai没有,而ai-1有的1)
-  10111
   10100
=  00011(为bi我们要找的)
3.ai xor 00011(此时ai再加上此数,则ai可包含ai-1里所有的1)
xor 10100
      00011
=   10111(ai)
4.ai-1所有1的位置上,ai里也是1
and 10111(ai)
       10011(ai-1)
=     10011(ai-1)

AC代码:

#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<cmath>
#include<numeric>
using namespace std;
#define endl '\n'
#define ll long long
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pii pair<int,int>
void func()
{
	int n;
	cin >> n;
	vector<ll>x(n);
	for (auto& xx : x)cin >> xx;
	cout << 0 << " ";
	for (int i = 1; i < n; i++)
	{
		ll xx = (x[i] | x[i - 1]) - x[i];
		x[i] ^= xx;
		cout << xx << " ";
	}
	cout << endl;
}
int main()
{
	cin.tie(0), cout.tie(0)->sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--)
	{
		func();
	}
	return 0;
}


2.1659B. Bit Flipping(思维+贪心)

原题链接:Problem - 1659B - Codeforces

题意比较简单理解。
思路:设选中的元素操作了m次,总操作数为k次,那么当前元素被翻转的k-m次,如果k-m为偶数则不改变,若为奇数则改变。
1.要使字典序最大,尽量使前面的元素为1
2.操作次数尽量少
从前往后遍历:
(1)若k为奇数,则遇到前面的1就要保护,不要让它翻转,即选中的这个1翻转次数为k-1,k-1为偶数,故保护了这个1;若遇到0,则不保护,让它翻转。
(2)若k为偶数,则遇到0就保护,因为这个0的翻转次数为k-1,可以翻转为1,遇到1则不翻转。
注意点:若从前往后遍历后有剩余的操作次数,但一定要执行完且不能对前面大数改变,即改变最小的那个数。

AC代码:

#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<cmath>
#include<numeric>
using namespace std;
#define endl '\n'
#define ll long long
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pii pair<int,int>
void func()
{
	int n, k;
	cin >> n >> k;
	int m = k;
	string s;
	cin >> s;
	vector<int>ans(n);
	if (k % 2 != 0)
	{
		for (int i = 0; i < n; i++)
		{
			if (s[i] == '1'&&k!=0)
			{
				ans[i]++;
				k--;
			}
			if (k == 0)break;
		}
		if (k)ans[n - 1] += k;
	}
	else
	{
		for (int i = 0; i < n; i++)
		{
			if (s[i] == '0'&&k!=0)//保证k!=0,若k==0则会是负数,break不了
			{
				ans[i]++;
				k--;
			}
			if (k == 0)break;
		}
		if (k)ans[n - 1] += k;
	}
	for (int i = 0; i < n; i++)
	{
		if ((m-ans[i]) % 2 == 0)
			cout << s[i];
		else
		{
			if (s[i] == '1')
				cout << '0';
			else
				cout << '1';
		}
	}
	cout << endl;
	for (int i = 0; i < n; i++)
	{
		cout << ans[i] << " ";
	}
	cout << endl;
}
int main()
{
	cin.tie(0), cout.tie(0)->sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--)
	{
		func();
	}
	return 0;
}

3.1746C. Permutation Operations

原题链接:Problem - 1746C - Codeforces

题意比较好理解。
思路:
为了使逆序对数量最少,且因为每次增量都会增加1,,要让大数少加,让小数多加。
注意a序列每个数字不同,且都是1~n,
可以用indx[x]=i记录x的位置为i
x大的先加,这样加的少,即先逆序输出indx[x]。

AC代码:

#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<cmath>
#include<numeric>
using namespace std;
#define endl '\n'
#define ll long long
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pii pair<int,int>
void func()
{
	int n;
	cin >> n;
	vector<int>a(n+1);
	vector<int>index(n+1);
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	for (int i = 1; i <= n; i++)
	{
		index[a[i]] = i;
	}
	//一定要执行n次
	for (int x = n; x >= 1; x--)
	{
		cout << index[x] << " ";
	}
	cout << endl;
}
int main()
{
	cin.tie(0), cout.tie(0)->sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--)
	{
		func();
	}
	return 0;
}


4.1753A1. Make Nonzero Sum (easy version)

原题链接:Problem - 1753A1 - Codeforces

题意:长度为n的序列a,只包含1和-1。

区间和计算公式为s[i,j]=a[i]-a[i+1]+a[i+2]-a[i+3]+...+a[j-1]-a[j]
要使这些区间和的总和为0。其中i可以等于j。
思路:
1.首先考虑一定不可以的情况:如果序列a的总和sum为奇数或者n为奇数,则不可以,输出-1;
2.可以的情况(sum为偶数,n为偶数)
保证拆分的小区间都为0,小区间最多2个就好了
将原序列进行拆分:
s={a[i],a[i+1]}
若a[i]==a[i+1],则还在s中(因为可得区间和为0)
若不相等,则各自分开成两个区间。

AC代码:

#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<cmath>
#include<numeric>
using namespace std;
#define endl '\n'
#define ll long long
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pii pair<int,int>
void func()
{
	int n;
	cin >> n;
	vector<int>a(n);
	int sum = 0;
	for (auto& x : a)
	{
		cin >> x;
		sum += x;
	}
	if (sum % 2 != 0)
	{
		cout << "-1" << endl;
		return;
	}
	vector<pii>ans;
	for (int i = 0, j = 1; j < n; i += 2, j += 2)
	{
		if (a[i] == a[j])
			ans.push_back({ i, j });
		else
		{
			ans.push_back({ i,i });
			ans.push_back({ j,j });
		}
	}
	cout << ans.size() << endl;
	for (int i = 0; i < ans.size(); i++)
	{
		cout << ans[i].first+1 << " " << ans[i].second+1 << endl;
	}
}
int main()
{
	cin.tie(0), cout.tie(0)->sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--)
	{
		func();
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值