这可能是我打那么多次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