A
题意
给你一个区间 [ l , r ] [l,r] [l,r] ,每次选择两两互质的 3 3 3 个数并删除,问最多可以这样操作几次?
思路
首先,两个相邻的数一定互质,即 gcd ( x , x + 1 ) = 1 \gcd(x,x+1)=1 gcd(x,x+1)=1,所以可以确定选择连续的三个数最优。
但是有些情况 x x x 和 x + 2 x+2 x+2 不互质,即当 x x x 为偶数时, gcd ( x , x + 2 ) = 2 \gcd(x,x+2)=2 gcd(x,x+2)=2,所以选择 x , x + 1 , x + 2 x,x+1,x+2 x,x+1,x+2 且 x x x 为奇数
所以只要计算 [ l , r ] [l,r] [l,r] 之间有多少个奇数,再将这个数除以 2 2 2,向下取整。
C++ 代码
#include<bits/stdc++.h>
using namespace std;
void solve(){
int l,r;
cin>>l>>r;
int rg=r-l+1;
int num=0;
if(l%2==1&&rg%2==1){
num=rg/2+1;
}else{
num=rg/2;
}
cout<<num/2<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
B
题意
给你 n n n 个数,操作 m m m 次,每次操作选择 [ l , r ] [l,r] [l,r] 区间内的数(注意是数字,不是下标) + 1 +1 +1 或 − 1 -1 −1,找到 每次 操作后数组中的最大值。
思路
只要考虑原数组中的最大值的加减。
设当前最大值为 m x mx mx
因为,每次如果将 < m x <mx <mx 的数 + 1 +1 +1,这些数最大也只能变成 m x mx mx,而下次操作若还想变得再大, [ l , r ] [l,r] [l,r] 区间内必须包含 m x mx mx,所以每次检查是否 l ≤ m x ≤ r l \le mx \le r l≤mx≤r ,如果符合, m x = m x + 1 mx=mx+1 mx=mx+1,否则不变
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
void solve(){
int n,m;
cin>>n>>m;
int mx=0;
for(int i=0;i<n;i++){
int ai;
cin>>ai;
mx=max(mx,ai);
}
for(int i=0;i<m;i++){
char c;
int l,r;
cin>>c>>l>>r;
if(mx>=l&&mx<=r){
if(c=='+') mx++;
else mx--;
}
cout<<mx<<" ";
}
cout<<endl;
}
signed main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
C
题意
给你 n n n 个数字, c 1 , c 2 , c 3 , . . . , c n c_1,c_2,c_3, ... ,c_n c1,c2,c3,...,cn
给你 a a a 和 b b b,每次操作可以选择一个 i i i,使 c i c_i ci 加上 a a a 或 b b b
定义 r a n g e ( c ) = max 1 ≤ i ≤ n { c i } − min 1 ≤ i ≤ n { c i } \displaystyle range(c)=\mathop{\max}_{1\le i\le n}\{c_i\}-\mathop{\min}_{1\le i\le n}\{c_i\} range(c)=max1≤i≤n{ci}−min1≤i≤n{ci}
你可以执行操作任意多次,使得 r a n g e ( c ) range(c) range(c) 最小,输出这个值
思路
可以证明,可控制的 r a n g e ( c ) range(c) range(c) 范围最多精确到 gcd ( a , b ) \gcd(a,b) gcd(a,b)。
那么,只需要把每一个 c i m o d gcd ( a , b ) c_i \bmod \gcd(a,b) cimodgcd(a,b) 得到的值排序,得到数组 v v v,让最右边的值,减去最左边的值。
但是这样不一定最小,因为还可以让最小的再 + gcd ( a , b ) +\gcd(a,b) +gcd(a,b) ,所以将 v v v 数组复制一遍,放到 v v v 后(每个元素加上 gcd ( a , b ) \gcd(a,b) gcd(a,b))
最终看最小的 c r − c l c_r-c_l cr−cl 就可以了( r = l + n − 1 r=l+n-1 r=l+n−1)
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=3e18;
void solve(){
int n,a,b;
cin>>n>>a>>b;
int p=__gcd(a,b);
vector<int> v(n);
for(int i=0;i<n;i++){
cin>>v[i];
v[i]%=p;
}
sort(v.begin(),v.end());
for(int i=0;i<n;i++){
v.push_back(v[i]+p);
}
int mn=inf;
for(int i=0;i<=n;i++){
mn=min(v[i+n-1]-v[i],mn);
}
cout<<mn<<endl;
}
signed main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}