CF1110C Meaningless Operations(思想题)

这可能是我打那么多次CF比赛时,做出来的最难的一道题了……而且这题也是个绝世好题……

题目链接:CF原网  洛谷

题目大意:$q$ 组询问,每次给定 $a$ 询问 $\gcd(a\&b,a\oplus b)$ 的最大值,其中 $1\le b<a$。规定 $\gcd(a,0)=a$。


真的是神仙题……

打几个表,我们发现如果 $a$ 的二进制表示中含有 $0$,比如 $100101100...$,也就是说不能表示成 $2^k-1$,那么他的答案就是所有 $2^k-1$ 中比 $a$ 大的最小的一个。

(虽然这个规律不是我打表找到的,是自己推出来的)

为什么呢?如果我们令 $b$ 为 $a$ 的位取反,那么 $a\&b=0,a\oplus b=2^k-1$。所以答案就是 $2^k-1$。可以证明答案不可能超过 $2^k-1$。

复杂度 $O(\log a)$。

那么 $a=2^k-1=(11111...)_2$ 怎么办呢?似乎大多数人都是暴力打出一个表然后直接调用的……

我的做法是:我们发现对于一个 $1\le b<a$,有 $a\&b=b,a\oplus b=a-b$。

那么 $\gcd(a\&b,a\oplus b)=\gcd(b,a-b)=\gcd(a,b)$!!!

$\gcd(a,b)$ 的最大值?就是 $a$ 的最大因数(不包括 $a$ 自己)。

总复杂度 $O(q\sqrt{a})$。

代码:

#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
    char ch=getchar();int x=0,f=0;
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int q,n;
int main(){
    q=read();
    while(q--){
        n=read();
        int c=1;
        while(c<=n) c<<=1;
        if(n!=c-1) printf("%d\n",c-1);
        else{
            bool flag=false;
            for(int i=2;i*i<=n;i++)
                if(n%i==0){printf("%d\n",n/i);flag=true;break;}
            if(!flag) printf("1\n");
        } 
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/1000Suns/p/10355991.html