题目背景
是一个热爱学习的奆佬,他尤其喜欢 gcd 和位运算。但是这天,老师给他出了一道非
常难的题, YY 知道仅凭自己的力量是做不出这道题的,于是他来请教你,希望你能设计
一个程序来帮助他。
YY
题目描述
给定你一个正整数 n ,求满足 1 ≤ b ≤ a ≤ n 且 gcd(a, b) == a xor b 的 a, b 的对数。
输入格式
从文件 gcd.in 中读入
第一行一个正整数 T 表示数据组数。
接下来 T 行每行一个正整数 n ,含义如上。
输出格式
输出到 gcd.out 文件中
共 n 行,格式为 Case x: ans ,其中 x 表示是是第几组数据, ans 表示该组数据的答案。
(建议复制粘贴)
样例
输入
2
7
20000000
输出Case 1: 4
Case 2: 34866117
数据范围
对于 100% 的数据, T ≤ 10000, n ≤ 3000000 。
对于 30% 的数据, n ≤ 5000 。
对于另外 20% 的数据, T ≤ 10, n ≤ 100000 。
我们发现a^b=c,a^c=b,而c是a和b的约数,所以我们只需要枚举a和c即可(O(nlogn))。
再加上求gcd的logn,总复杂度就是O(nlog2n)。
但是我们a-b<=a^b又gcd(a,b)=c,a-b>=c,所以a-b==c,从而不用求gcd了。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cstdlib> #include<algorithm> #define ll long long #define il inline #define db double using namespace std; il int gi() { int x=0,y=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') y=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*y; } il int gcd(int a,int b) { b!=0?gcd(b,a%b):a; } int ans[3000000]; int main() { freopen("gcd.in","r",stdin); freopen("gcd.out","w",stdout); for(int c=1;c<=3000000;c++) for(int a=c<<1;a<=3000000;a+=c) { int b=a-c; if(c==(a^b)) ans[a]++; } for(int i=1;i<=3000000;i++) ans[i]+=ans[i-1]; int T=gi(); for(int i=1;i<=T;i++) { int n=gi(); printf("Case %d: %d ",i,ans[n]); } return 0; }