Codeforces Round 945 (Div. 2)
Codeforces Round 945 (Div. 2)
A. Chess For Three 签到
题意:
三个人两两下棋,胜者得 \(2\) 分,败者得 \(0\) 分,平局双方各得 \(1\) 分。 现在给你三个人的得分(已经升序排序)。
求最多平局个数,如果得分不合法输出 \(-1\)。
思路:
考虑两种情况,
\(a+b>=c\) 时:两人分别和 \(c\) 去和棋,剩下部分两个人互相和棋。如果剩余为奇数,那么说明不合法。
\(a+b<c\) 时:两人分别和 \(c\) 去和棋,\(c\) 剩下部分得分去战胜别人获得,如果剩余为奇数,那么说明不合法。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define all(u) u.begin(), u.end()
#define endl '\n'
#define debug(x) cout<<#x<<":"<<x<<endl;
typedef pair<int, int> PII;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10, M = 105;
const int mod = 1e9 + 7;
const int cases = 1;
void Showball(){
int a,b,c;
cin>>a>>b>>c;
int t=a+b-c;
if(t&1) return cout<<"-1\n",void();
if(t<0) cout<<a+b<<endl;
else cout<<c+(a+b-c)/2<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
if(cases) cin>>T;
while(T--)
Showball();
return 0;
}
B. Cat, Fox and the Lonely Array 拆位+贪心
题意:
给你 \(n\) 个非负整数,求出满足每 \(k\) 个连续元素按位或的结果相等的最小 \(k\) 值。
思路:
位运算题目,拆位,这样整数的取值只有 \(0\) 和 \(1\) , 那么按位或的值只有 \(0\) 和 \(1\) 两种取值。
对于 \(0\) 这种情况,必须所有值全部为 \(0\) ,此时 \(k=1\)。
对于 \(1\) 这种情况,贪心考虑,显然最小的 \(k\) 就是最长连续 \(0\) 的长度 + \(1\) 。
最长连续 \(0\) 的长度用双指针维护即可。
代码:
void Showball(){
int n;
cin>>n;
vector<int> a(n);
for(int i=0;i<n;i++) cin>>a[i];
int ans=1;
for(int i=0;i<=20;i++){
for(int j=0;j<n;j++){
int cnt=1,k=j;
while(k<n&&!(a[k]>>i&1)) cnt++,k++;
if(cnt==n+1) cnt=1;
ans=max(ans,cnt);
if(j==k) continue;
j=k-1;
}
}
cout<<ans<<endl;
}
C. Cat, Fox and Double Maximum
题意:
给你一个长度为 \(n\) 的排列 \(p\), 构造一个新的长度为 \(n\) 的排列 \(q\) ,不妨令 \(a_i=p_i+q_i\) 。
若满足 \(a_{i-1}<a_i\) 并且 \(a_i>a_{i+1}\) 那么我们称 \(a_i\) 为局部最大值。请你构造出 \(q\) 使得局部最大值的数量最大。
思路:
为了使得局部最大值的数量最多,那么局部最大值一定全部排在奇数位或者偶数位。
如果 \(1\) 在奇数位,我们就构造局部最大值在偶数位。反之,将局部最大值构造在奇数位。
这里假设 \(1\) 在奇数位,那么我们将 \(1\) ~ \(n/2\) 之间的数全部安排在奇数位上,并且按照 \(p_i\) 值降序安排。
这样就可以保证奇数位的所有数都是小于等于 \(n+1\) 的。
接着将 \(n/2+1\) ~ \(n\) 之间的数全部安排在偶数位上,并且按照 \(p_i\) 值降序安排。
这样就可以保证偶数位的所有数都是大于 \(n+1\) 的。那么偶数位就全部满足局部最大值的性质了。
如果 \(1\) 在偶数位,反过来处理即可。
代码:
void Showball(){
int n;
cin>>n;
vector<int> a(n+1);
vector<PII> odd,even;
int ok=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==1) ok=i&1;
if(i&1) odd.pb({a[i],i});
else even.pb({a[i],i});
}
sort(all(odd));
sort(all(even));
vector<int> ans(n+1);
int t=(ok?n/2:n);
for(auto [v,p]:odd) ans[p]=t--;
t=(ok?n:n/2);
for(auto [v,p]:even) ans[p]=t--;
for(int i=1;i<=n;i++) cout<<ans[i]<<" \n"[i==n];
}
D. Cat, Fox and Maximum Array Split 交互题
题意:
给你 \(n\) 和 \(k\) , 有一个隐藏的数组 \(a\) ,定义 \(f(l,r)=(r-l+1)·\max_{x=l}^{r}a_x\)。
你可以进行 \(2n\) 次询问,每次询问给出 \(l,x\) 返回一个整数 \(p\) ,满足 \(f(l,r)=x\) 的最小正整数 \(r\) 。
若不存在这样的 \(r\) , 返回 \(n+1\) 。
通过询问后,你需要找到或者确定不存在这样的 \(m\) 。使得将数组分割成 \(k\) 个子数组,使得所有子数组 \(l_i,r_i\) ,满足 \(f(l_i,r_i)=m\)。
思路:
考虑答案只可能为最大值的倍数,那么我们就可以询问 \(n\) 次找到最大值。然后枚举倍数,因为最多只用枚举到
\(n/k\) 倍,所以询问次数不会超过 \(2n\) 次。然后判断,维护答案即可。
代码:
void Showball(){
int n,k;
cin>>n>>k;
auto ask=[&](int l,int x){
cout<<"? "<<l<<" "<<x<<endl;
int ret;
cin>>ret;
return ret;
};
int maxn=0;
for(int i=1;i<=n;i++){
if(ask(1,i*n)==n){
maxn=i;
break;
}
}
int ans=-1;
for(int i=1;i<=n/k;i++){
int m=i*maxn;
int cnt=0,r=1;
while(r<=n){
r=ask(r,m);
if(r==n+1){
cnt=0;
break;
}
r++;
cnt++;
if(cnt==k&&r!=n+1){
cnt=0;
break;
}
}
if(cnt==k) ans=max(ans,m);
}
cout<<"! "<<ans<<endl;
int t;
cin>>t;
}