Codeforces Round #769 (Div. 2)

Posted on 2022-02-09 15:42  Capterlliar  阅读(57)  评论(0编辑  收藏  举报

C. Strange Test

题意:给出两个数a和b (a<b),每次可以从以下三个操作中选一个:1.a=a+1;  2.b=b+1;  3.a=a|b.   求使a和b相等所需最小操作数。(the sum of b is less than 1e6)

解:a小于b嘛,那当它们尾数一样的时候或运算一下,就相等了。现在考虑怎么让它们尾数一样。很简单,要么加a,要么加b。那就两个都试一遍。直接算有点烦,尤其是a,那就枚举。a枚举到b就可以了,b的话,题目把b的和小于1e6加深,疯狂暗示枚举个十倍八倍的也不成问题。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 1000005
#define maxn 1005
#define maxm 305
#define eps 0.00000001
#define inf 0x7fffffff
#define mod 998244353
//#define int long long
int a,b;
signed main() {
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&a,&b);
        int ans=b-a;
        for(int i=a;i<=b;i++){
            if((i|b)==b)
                ans=min(ans,i-a+1);
        }
        for(int i=b;i<=b<<2;i++){
            if((i|a)==i)
                ans=min(ans,i-b+1);
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

D. New Year Concert

题意:给出一串数。对于它的每一个前缀,求最少修改多少个数后,能使它的每一个子数组的gcd,不等于这个子数组的长度。(不加逗号要断气了

解:肉眼观察一下,首先这串数里不能有1。其次连着两个的不能都是2的倍数,连着3个的不能是3的倍数,etc。如果修改一个数,那么包含这个数的任意子数组都可以符合要求。

既然要一个一个输出答案,那么考虑一个一个往里加数。加之前假设这串数已经满足要求了,那么可以不动其中的任何一个,只考虑包含新加进来数的子数组。但是每个都算一遍还是n2,会超时。有一种感觉是之前长度已经很长的子数组,加入新的一个数多半还是满足要求的。考虑寻找这个分界点。已知gcd越加越小,那么之前gcd已经小于长度的子数组多加进来一个数,显然满足要求,那么每次可以跳过这些数。如果之前gcd比长度大,那加进来一个新的数就有可能相等了,有嫌疑,留着。如果找到违规子数组,优先修改末尾,也就是新加进来的数,这样后面的都不用判了。(改第一个的话样例三会提醒你,说,谢谢样例三。

然后就是快速求区间gcd,懒人专供线段树,不知道为什么开4倍空间过不去,非要8倍,那就8倍吧。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 200005
#define maxn 1005
#define maxm 305
#define eps 0.00000001
#define inf 0x7fffffff
#define mod 998244353
//#define int long long
int n,a[maxx];
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}

int tr[maxx<<4]={0};
void build(int now,int l,int r){
    if(l==r) {
        tr[now] = a[l];
        return;
    }
    int mid=(l+r)/2;
    build(now*2,l,mid);
    build(now*2+1,mid+1,r);
    tr[now]=gcd(tr[now*2],tr[now*2+1]);
}
int query(int now,int l,int r,int s,int e){
    if(s<=l&&r<=e)
        return tr[now];
    int a=0,b=0;
    int mid=(l+r)/2;
    if(s<=mid)
        a=query(now*2,l,mid,s,e);
    if(mid<e)
        b=query(now*2+1,mid+1,r,s,e);
    return gcd(a,b);
}


signed main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,1,n);
    int j=1,ans=0;
    for(int i=1;i<=n;i++){
        while(query(1,1,n,j,i)<i-j+1)
            j++;
        if(query(1,1,n,j,i)==i-j+1){
            ans++;
            j=i+1;
        }
        printf("%d ",ans);
    }
    printf("\n");
    return 0;
}
View Code