Codeforces Global Round 18(A-C)
第一次写,表达不清晰的请见谅。
A.Closing The Gap
题意:
给一个序列a,每次操作可以让序列a中一个数加1和另一个数减1
在多次操作后,问 m a x ( a ) − m i n ( a ) max(a) - min(a) max(a)−min(a)的最小值。
思路:
不难发现,我们的总和是不变的。在没有操作次数的限制下,我们一定可以把所有数弄相等或者差1。所以我们只需要算出总和看能不能平分,可以的话答案就是0,否则就是1。
代码
#include<bits/stdc++.h>
#include<set>
#include<deque>
#include<map>
using namespace std;
typedef long long ll;
typedef pair<ll,ll>PII;
const int N = 1e6+10,inf = 0x3f3f3f3f;
int a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--){
int n;
cin >> n;
ll sum = 0;
for(int i = 1; i <= n; i++){
cin >> a[i];
sum += a[i];
}
if(sum % n == 0){
cout << 0 << endl;
}
else{
cout <<1<<endl;
}
}
return 0;
}
/*
input
3
3
10 10 10
4
3 2 1 2
5
1 2 3 1 5
output
0
0
1
*/
B.And it’s Non-Zero
题意:
给一个l(左边界)r(右边界),我们的目的是找到 最少从l到r的所有数中取去多少数后,
可以让l到r这个区间的按位与运算结果非0。
思路:
因为按位与是有0得0,
要使答案非0,我们就要保证最后留下的每个数其二进制中在某个相同的位置全是1。
我们只需要在二进制中寻找每个数中每一位出现1的次数,找到出现次数的最大值。
这就说明这是我们需要留下的数。我们再用区间长度去减去它便可得到答案——要取出的数。
我们可以发现数据范围是 2 e 5 2e5 2e5 也就是说我们的数转换为二进制最多就20位
我们需要计算出一个区间中每个数每一位1出现的次数,在测试组数为
1
e
4
1e4
1e4的情况下,我们每次都去跑完区间是肯定会
T
l
e
Tle
Tle的 (我就tle了) ,所以我们要提前初始化数据。
#include<bits/stdc++.h>
#include<set>
#include<deque>
#include<map>
using namespace std;
typedef long long ll;
typedef pair<ll,ll>PII;
const int N = 2e5+10,inf = 0x3f3f3f3f;
int a[N][20]; // a[i][j] = 1 表示1——i之间所有数在其二进制下第j位上有1个1
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
//计算从1到2e5中每个数中二进制每一位1的个数
for(int i = 1; i <= N; i++){
for(int j = 0 ; j < 20 ; j ++){
if(i & (1 << j) ) a[i][j]++;
a[i][j] += a[i-1][j]; // 前缀和维护
}
}
int t;
cin >> t;
while(t--){
int l , r;
cin >> l >> r;
int ans = 0;
//找到这个区间中二进制1出现最多的次数
for(int i = 0; i <20; i++){
ans = max(ans,a[r][i] - a[l-1][i]);
}
ans = (r - l + 1) - ans;
cout << ans <<endl;
}
return 0;
}
/*
input
5
1 2
2 8
4 5
1 5
100000 200000
output
1
3
0
2
31072
*/
C.Menorah
题意:
给两个由1和0组成的字符串 a,b。我们每次可以对a串的1进行操作:
维持当前位置1不变,其他位置的1变成0,0变成1;
问我们能否通过该操作把a串变成b串,如果可以 就输出最小操作次数,否则输出-1
思路:
通过观察,我们可以发现:
/*
1010 我们操作为1 的位置1
|
1101 我们再操作原先为 0 的位置2
|
0110 (结果)
*/
相当于我们可以通过两次操作交换原串中1和0的位置,并让其他位置保持不变。
于是:交换一次位置我们就要操作两次
我们要把从a串状态变成b串:
计算不相等的位置中 a串1与0的数量是否相等,相等的话我们可以用交换操作达成目的此时答案是
交换次数 * 2
特殊情况:
如果a串与b串中有同一位置等于1
我们就可以优先操作该位置,操作后该位置不变,之前与b串不相等的地方会相等,相等的地方会不等。
/*
a:101 0101
b:101 1010
操作位置1
a:1 10 1010
b:1 01 1010
*/
所以我们也可以计算原a串中相同位置的0与1的数量是否相等,相同1的数量要减1(减去用来翻转的第一次),如果相同,我们同样可以通过交换操作达成目标,此时答案是交换次数 * 2 + 我们第一次的1次翻转
两个情况取最小值既是答案
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
using namespace std;
const int N = 1e5 + 5;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef pair<int,int> pe;
int a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t -- ){
int n;
cin >> n;
string a , b;
cin >> a >> b;
int len = a.length();
int ans = INF;
int an = 0, bn = 0, cn = 0, dn = 0;
for(int i = 0; i < len; ++ i){
if(a[i] != b[i]){
if(a[i] == '1') an++;
else bn ++;
}
if(a[i] == b[i]){
if(a[i] == '1') cn++;
else dn ++;
}
}
if(an == bn) ans = min(ans , an * 2);
if(cn){
cn --;
if(cn == dn) ans = min(ans , cn * 2 + 1);
}
if(ans == INF) cout << - 1 << endl;
else cout << ans << endl;
}
return 0;
}