A. Make A Equal to B
Sample input
5
3
1 0 1
0 0 1
4
1 1 0 0
0 1 1 1
2
1 1
1 1
4
1 0 0 1
0 1 1 0
1
0
1
Sample output
1
2
0
1
1
题意:
你有两个长度为n的数组a和b,你可以进行一次操作,将a数组的某个位置的数取反,或者将这个数组打乱成任意顺序,问将a数组变成b数组最少需要的操作次数是多少
思路:
就统计一下a数组和b数组的’0’的差值的绝对值,然后再统计a数组和b数组不同数的位置的个数,这个不同位置的个数是一定大于等于’0’的差值的绝对值的,如果相等的话那就是这个数,如果大于的话就是差值绝对值+1就行,下面看代码把
#include<bits/stdc++.h>
using namespace std;
const int N = 310;
int a[N],b[N];
void solve(){
int n;
scanf("%d",&n);
int cnt = 0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),cnt += a[i];
for(int i=1;i<=n;i++) scanf("%d",&b[i]),cnt -= b[i];
int butong = 0;
for(int i=1;i<=n;i++){
butong += a[i] != b[i];
}
cnt = abs(cnt);
if(butong == cnt){
printf("%d\n",cnt);
}
else{
printf("%d\n",cnt+1);
}
}
int main(){
int _;
scanf("%d",&_);
while(_--) solve();
return 0;
}
B. Playing with GCD
Sample input
4
1
343
2
4 2
3
4 2 4
4
1 1 1 1
Sample output
YES
YES
NO
YES
题意:
给你一个长度为n的数组a,问你能不能构造出一个长度为n+1的数组b,使得任意的 i , gcd(b[i],b[i+1]) = a[i]
思路:
gcd(b[i],b[i+1]) = a[i] , gcd(b[i-1,b[i]) = a[i-1],所以说b[i]至少为lcm(a[i-1],a[i]),也可以是lcm(a[i-1],a[i])的倍数,但是越大的话不如越小优,因为越大的话他和他相邻的数的gcd可能会变大,那就可能导致答案错误,思路就是这个,下面看代码吧:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N],b[N];
void solve(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
b[1] = a[1],b[n+1] = a[n];
for(int i=2;i<=n;i++) b[i] = a[i-1]*a[i]/__gcd(a[i-1],a[i]);
for(int i=1;i<=n;i++){
if(__gcd(b[i],b[i+1]) != a[i]){
puts("NO");
return;
}
}
puts("YES");
}
int main(){
int _;
scanf("%d",&_);
while(_--) solve();
return 0;
}
C1. Good Subarrays (Easy Version)
Sample input
3
3
1 2 3
3
1 1 1
4
2 1 4 3
Sample output
6
3
7
题意:
一个数组是好的就意味着这个数组的所有元素值都大于等于它在这个数组中的相对位置,现在给你一个长度为n的数组a,问你它有多少个子数组是好的。
思路:
我想的是dp,f[i]表示的是以第i个数为结尾,最左边能扩展到的位置,如果当前的数为a[i],代表它最大能当a[i]个数的数组的最后一个,转移的时候就只看前一个能扩展到什么位置就行,下面看代码吧
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int a[N],f[N];
void solve(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
f[i] = 0;
}
f[1] = 1;
for(int i=2;i<=n;i++){
f[i] = i;
if((i-f[i-1]) < a[i]) f[i] = f[i-1];
else f[i] = max(f[i-1] + 1,i - a[i] + 1);
}
long long ans = 0;
for(int i=1;i<=n;i++) ans += i + 1 - f[i];
printf("%lld\n",ans);
}
int main(){
int _;
scanf("%d",&_);
while(_--) solve();
return 0;
}
D. Equal Binary Subsequences
Sample input
4
2
1010
3
100010
2
1111
2
1110
Sample output
0
1 2
2 3 5
1 2 5
3 2 3 4
1 4
-1
题意:
给你一个长度为2*n的01串,你可以选择一些位置,组成一个子序列,然后将这个子序列循环右移,问你能不能通过最多一次这种操作分出两个长度为n的相同的子序列
思路:
如果1的个数是奇数,那么一定不可能,如果1的个数是偶数,那么一定能构造出来,借鉴了一位大佬的思路,成对的看,下面咱们看一个例子:
1 0 1 0 1 0 1 0
将这个序列循环右移之后的结果就是
0 1 0 1 0 1 0 1
这不就相当于是两两交换吗
然后做法就是两个两个的看,如果主01串相邻两个位置的值不一样就记录一下,都记录的是10这个串的位置,最后两两交换就行,做法就是奇数位置的10的1和偶数位置10的0进行交换,那么这两个位置的值就变成了00和11,那么最后这2n个数的答案就是奇数位置,这个思路非常妙,下面看代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
char s[N];
void solve(){
int n;
scanf("%d%s",&n,s+1);
n <<= 1;
vector<pair<int,int> > q;
for(int i=1;i<=n;i+=2){
if(s[i] != s[i+1]){
if(s[i] == '1') q.push_back({i,i+1});
else q.push_back({i+1,i});
}
}
if(q.size()&1){
puts("-1");
return;
}
printf("%d ",q.size());
for(int i=0;i<q.size();i++){
if(i & 1) printf("%d ",q[i].first);
else printf("%d ",q[i].second);
}
puts("");
for(int i=1;i<=n;i++) if(i & 1) printf("%d ",i);
puts("");
}
int main(){
int _;
scanf("%d",&_);
while(_--) solve();
return 0;
}