Codeforces Round #838 (Div. 2)

A. Divide and Conque

如果原本sum是偶数不操作,如果原本是奇数,则对于 a1....an 计算每个数从奇数变成偶数或者从偶数变成奇数需要的最少次数 pi , 对p取min即可

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int maxn = 1e5+10;
ll a[maxn];
ll times[maxn];
void solve(){
    int n;cin>>n;
    for(int i = 1;i<=n;i++)
        cin>>a[i];
    ll sum = 0;
    for(int i = 1;i<=n;i++)
        sum+=a[i];
    if(sum%2==0){
        cout<<0<<endl;
        return;
    }
    int mi = 1e9;
    for(int i = 1;i<=n;i++){
        int j = a[i]%2;
        int ss = 0;
        while(a[i]%2==j){
            ss++;
            a[i]/=2;
        }
        mi = min(ss,mi);
    }
    cout<<mi<<endl;
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t = 1;
    cin>>t;
    while(t--){
        solve();
    }
}

B. Make Array Good

根据题意可知,如果要所有数满足条件,则最终的数列a排序完应该满足条件: ai=ai−1∗c(c>=1) ,那么很自然我们直接进行排序然后以最小的数为a1,后面的数依次操作变成最近的满足条件的数就好。

同时易证,每次操作最多一次

  1. ai=ai−1 ,不用操作
  2. ai<ai−1 ,从 a1 开始考虑,由于 a2>a1 ,如果 a2 要变成 a1 的倍数,那直接变成 ca1(c>=1) 即可,同时操作的范围不会超过 自然不会超过本身a1,自然不会超过a2本身
  3. ai>ai−1 ,直接变成 ai−1 的两倍就好了
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int maxn = 1e5+10;
ll a[maxn];
pair<int,int>p[maxn];
void solve(){
    int n;cin>>n;
    for(int i = 1;i<=n;i++)
        cin>>a[i];

    for(int i =1;i<=n;i++){
        p[i] = {a[i],i};
    }
    sort(p+1,p+n+1);
    int now = p[1].first;
    vector<pair<int,int>>ans;
    for(int i = 2;i<=n;i++){
        if(p[i].first==now)
            continue;
        else{
            if(p[i].first%now==0){
                now = p[i].first;
            }
            else if(now>p[i].first){
                ans.push_back({p[i].second,  now-p[i].first});
            }
            else{
                int pre =(p[i].first/now+1)*now;
                ans.push_back({p[i].second, pre - p[i].first});
                now = pre;
            }
        }
        //cout<<now<<" "<<i<<endl;
    }
    int len = ans.size();
    cout<<len<<endl;
    for(auto j:ans)
        cout<<j.first<<" "<<j.second<<endl;
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t = 1;
    cin>>t;
    while(t--){
        solve();
    }
}

C. Binary Strings are Fun

题意很绕,大概就是说对于一串二进制01字符串s(下标从1开始)而言,截取每个开头到奇数下标的范围 s[1..i] 子字符串s1,s1中的median(字符串中最多的那个字符)要位于所有奇数下标上。这样的字符串是good的

然后对于一个字符串s而言,他有一个拓展串s2概念,指的是s2中的奇数下标2k-1分别对应s中的k下标。

问你,对于一个字符串s,其子串 s[1..i] 的good拓展串之和

我们可以发现,对于一个字符串0110而言,其拓展串想good只能0 1 1 0 1 0 0这样填入,在两个1中间如果填1则最后的0是就不满足了,也就是说事实上只有在尾部的连续0串或者1串间我们才能随意放入数字。

那我们遍历过去顺便统计一下尾部连续的长度,统计和即可。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int maxn = 1e5+10;
const int mod = 998244353;
ll a[maxn];
pair<int,int>p[maxn];
//奇数长度二进制串
//到i为之最多的i就是median,要每个奇数位都是median

long long qpow(long long base, long long power) {
    long long result = 1;
    while (power > 0) {
        if (power & 1) {//此处等价于if(power%2==1)
            result = result * base % mod;
        }
        power >>= 1;//此处等价于power=power/2
        base = (base * base) % mod;
    }
    return result;
}



void solve(){
    int n;cin>>n;
    string s;cin>>s;
    if(n==1){
        cout<<1<<endl;
        return;
    }
    s = '?'+s;
    int len = 1;
    char now = s[1];
    ll ans = 1;
    for(int i = 2;i<=n;i++){
        if(now==s[i]){
            len++;
        }
        else{
            now = s[i];
            len = 1;
        }
        ll pre = 1;
        pre*= qpow(2,len-1);
        pre%=mod;
        ans = (ans+pre)%mod;
        //cout<<i<<" "<<ans<<endl;
    }
    cout<<ans<<endl;
}
//如果最后有连续的1或者0,那么从那一段开始我们可以随意选任意的1或者0,除外我们必须填唯一

signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t = 1;
    cin>>t;
    while(t--){
        solve();
    }
}

D. GCD Queries

交互题,我们可以发现一个性质, gcd(a,b)<=min(a,b) ,但当a或者b有0时, gcd(a,b)<=max(a,b)

由于是一个purmutation,对于abc三个数,只要有一个0在abc中,那么我们最后留下的一定是0和一个较大的数,这样一来,我们一定能保证0在x和y中。

#include <bits/stdc++.h>
using namespace std;

int ask(int i, int j) {
    cout << "? " << i << " " << j << endl;
    int t; cin >> t; return t;
}

int ans(int i, int j) {
    cout << "! " << i << " " << j << endl;
    int t; cin >> t; return t;
}


void solve() {
    int n;
    cin >> n;
    int x = 1, y = 2;
    int now = ask(x, y);
    for(int i = 3; i <= n; i ++) {
        int s = ask(x, i), t = ask(y, i);
        int xx = x, yy = y;
        if(s > now) {
            xx = x, yy = i;
            now = s;
        }
        if(t > now) {
            xx = y, yy = i;
            now = t;
        }
        x = xx, y = yy;
    }
    ans(x, y);
}
int main() {
    int tc;
    cin >> tc;
    for(; tc; tc --) solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值