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;
}