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;
}
posted @ 2024-05-21 00:33  Showball  阅读(33)  评论(0编辑  收藏  举报