文章目录
A. Bestie
题目大意:
给你一个由n个整数a1,a2,…,an组成的数组a。朋友要求你使数组中所有数字的最大公除数(GCD)等于1。 在一次操作中,你可以做以下事情。
在数组中选择一个任意的索引1≤i≤n。
使ai=gcd(ai,i),其中gcd(x,y)表示整数x和y的GCD.这种操作的成本是n-i+1.
你需要找到我们需要执行的最小的操作总成本,使所有数组数字的GCD变成等于1。
输入
每个测试由多个测试案例组成。第一行包含一个整数t(1≤t≤5000)–测试案例的数量。测试用例的描述如下。
每个测试用例的第一行包含一个整数n(1≤n≤20)–数组的长度。
每个测试用例的第二行包含n个整数a1,a2,…,an(1≤ai≤10^9)–数组的元素。
输出
对于每个测试用例,输出一个整数–为了使数组中所有数字的GCD等于1而需要执行的最小总运算成本。
我们可以证明,总是有可能做到的。
思路:
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<pair<int,int>> vpii;
#define all(a) a.begin(), a.end()
#define nl '\n'
#define debug() cout << "debug:"
const int inf = 0x3f3f3f3f;
const int maxn = 2e5+5;
void solve(){
int n, t, x;
scanf("%d", &n);
int d = 0;
for (int i = 1; i <= n; i++){
int x;
scanf("%d", &x);
d = __gcd(d, x);
}
if(d == 1){
puts("0");
return;
}
if(__gcd(d, n) == 1)
puts("1");
else if(__gcd(d, n - 1) == 1)
puts("2");
else
puts("3");
}
int main(){
//ios::sync_with_stdio(0);
//freopen("in", "r", stdin);
int t = 1;
cin>>t;
while(t--)
solve();
return 0;
}
B. Ugu
题目大意:
二进制字符串是指仅由字符0和1组成的字符串,给你一个二进制字符串s1s2…sn。有必要使这个字符串在最少的操作中不递减。换句话说,每个字符都不能少于前一个。在一次操作中,你可以做以下工作。
在字符串中选择一个任意的索引1≤i≤n。
对于所有的j≥i,将第j个位置的值改为相反的值,也就是说,如果sj=1,则使sj=0,反之亦然。
要使该字符串不递减所需的最少操作数是多少?
输入
每个测试由多个测试案例组成。第一行包含一个整数t(1≤t≤10^4)–测试案例的数量。测试用例的描述如下。
每个测试用例的第一行包含一个整数n(1≤n≤10^5)–字符串的长度。
每个测试案例的第二行包含一个长度为n的二进制字符串s。
保证所有测试用例的n之和不超过2⋅10^5。
输出
对于每个测试用例,输出一个整数–使字符串不递减所需的最小操作数。
思路:
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<pair<int,int>> vpii;
#define all(a) a.begin(), a.end()
#define nl '\n'
#define debug() cout << "debug:"
const int inf = 0x3f3f3f3f;
const int maxn = 2e5+5;
void solve(){
int t, n, f[maxn] = {0};
char s[maxn];
scanf("%d%s", &n, s + 1);
s[0] = '0';
for (int i = 1; i <= n; i++)
f[i] = f[i - 1] + (s[i] != s[i - 1]);
printf("%d\n", max(f[n] - 1, 0));
}
int main(){
//ios::sync_with_stdio(0);
//freopen("in", "r", stdin);
int t = 1;
cin>>t;
while(t--)
solve();
return 0;
}
C1. Sheikh (Easy version)
题目大意:
这是该问题的简单版本。唯一不同的是,在这个版本中,q=1。
给你一个整数数组a1,a2,…,an。
数组[l,r]的一个子段的成本,1≤l≤r≤n,是值f(l,r)=sum(l,r)-xor(l,r),其中sum(l,r)=al+al+1+…+ar,xor(l,r)=al⊕al+1⊕…⊕ar(⊕代表位向XOR)。
你将有q=1个查询。每个查询由一对数字Li, Ri给出,其中1≤Li≤Ri≤n。你需要找到具有最大值f(l,r)的子段[l,r],Li≤l≤r≤Ri。如果有几个答案,那么你需要在其中找到一个长度最小的子段,也就是r-l+1的最小值。
输入
每个测试由多个测试案例组成。第一行包含一个整数t(1≤t≤10^4)–测试案例的数量。测试用例的描述如下。
每个测试用例的第一行包含两个整数n和q (1≤n≤10^5, q=1) - 阵列的长度和查询次数。
每个测试案例的第二行包含n个整数a1,a2,…,an(0≤ai≤10^9)–数组元素。
每个测试案例接下来的q行中的第i行包含两个整数Li和Ri(1≤Li≤Ri≤n)–我们需要在其中找到段的边界。
保证所有测试案例的n之和不超过2⋅105。
保证L1=1,R1=n。
输出
对于每个测试案例,打印q对数字Li≤l≤r≤Ri,使f(l,r)的值最大,并且其中r-l+1的长度最小。如果有几个正确的答案,打印其中任何一个。
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<pair<int, int>> vpii;
#define all(a) a.begin(), a.end()
#define nl '\n'
#define debug() cout << "debug:"
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 5;
ll s[N], x[N];
int nonz_left[N], nonz_right[N], a[N];
ll f(int l, int r){
return s[r] - s[l - 1] - (x[r] ^ x[l - 1]);
}
void solve(){
int n, q;
cin >> n >> q;
for (int i = 1; i <= n; i++){
cin >> a[i];
s[i] = s[i - 1] + a[i];
x[i] = x[i - 1] ^ a[i];
nonz_left[i] = a[i] == 0 ? nonz_left[i - 1] : i;
}
nonz_right[n + 1] = n + 1;
for (int i = n; i >= 1; i--)
nonz_right[i] = a[i] == 0 ? nonz_right[i + 1] : i;
while (q--){
int L, R;
cin >> L >> R;
int l = L, r = R;
ll ans = f(l, r);
if (ans == 0){
cout << l << ' ' << l << '\n';
continue;
}
int i = L;
while (i <= R and f(i, R) == ans){
int j = R;
while (j >= i){
if (f(i, j) == ans){
if (j - i < r - l){
l = i;
r = j;
}
}
else
break;
j = nonz_left[j - 1];
}
i = nonz_right[i + 1];
}
cout << l << ' ' << r << '\n';
}
}
int main(){
// ios::sync_with_stdio(0);
// freopen("in", "r", stdin);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
C2. Sheikh (Hard Version)
题目大意:
这是该问题的困难版本。唯一不同的是,在这个版本中q=n。
你将得到一个整数数组a1,a2,…,an。
数组[l,r]的一个子段的成本,1≤l≤r≤n,是值f(l,r)=sum(l,r)-xor(l,r),其中sum(l,r)=al+al+1+…+ar,xor(l,r)=al⊕al+1⊕…⊕ar(⊕代表位向XOR)。
你将有q个查询。每个查询由一对数字Li, Ri给出,其中1≤Li≤Ri≤n。你需要找到具有最大值f(l,r)的子段[l,r],Li≤l≤r≤Ri。如果有几个答案,那么你需要在其中找到一个长度最小的子段,也就是r-l+1的最小值。
输入
每个测试由多个测试案例组成。第一行包含一个整数t(1≤t≤10^4)–测试案例的数量。测试用例的描述如下。
每个测试用例的第一行包含两个整数n和q(1≤n≤10^5,q=n)–阵列的长度和查询次数。
每个测试用例的第二行包含n个整数a1,a2,…,an (0≤ai≤10^9) - 数组元素。
每个测试案例接下来的q行中的第i行包含两个整数Li和Ri(1≤Li≤Ri≤n)–我们需要在其中找到段的边界。
保证所有测试案例的n之和不超过2⋅10^5。
保证L1=1,R1=n。
输出
对于每个测试案例,打印q对数字Li≤l≤r≤Ri,使f(l,r)的值最大,并且其中r-l+1的长度最小。如果有几个正确的答案,打印其中任何一个。
code :
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<pair<int, int>> vpii;
#define all(a) a.begin(), a.end()
#define nl '\n'
#define debug() cout << "debug:"
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 5;
ll s[N], x[N];
int nonz_left[N], nonz_right[N], a[N];
ll f(int l, int r){
return s[r] - s[l - 1] - (x[r] ^ x[l - 1]);
}
void solve(){
int n, q;
cin >> n >> q;
for (int i = 1; i <= n; i++){
cin >> a[i];
s[i] = s[i - 1] + a[i];
x[i] = x[i - 1] ^ a[i];
nonz_left[i] = a[i] == 0 ? nonz_left[i - 1] : i;
}
nonz_right[n + 1] = n + 1;
for (int i = n; i >= 1; i--)
nonz_right[i] = a[i] == 0 ? nonz_right[i + 1] : i;
while (q--){
int L, R;
cin >> L >> R;
int l = L, r = R;
ll ans = f(l, r);
if (ans == 0){
cout << l << ' ' << l << '\n';
continue;
}
int i = L;
while (i <= R and f(i, R) == ans){
int j = R;
while (j >= i){
if (f(i, j) == ans){
if (j - i < r - l){
l = i;
r = j;
}
}
else
break;
j = nonz_left[j - 1];
}
i = nonz_right[i + 1];
}
cout << l << ' ' << r << '\n';
}
}
int main(){
// ios::sync_with_stdio(0);
// freopen("in", "r", stdin);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}