题意:求小于等于n的(a,b) 满足 a>b且 axorb=gac(a,b)的所以(a,b)数目
n有30000000这么大 所以一直在想什么O(1)的算法 然而后来才发现 T放宽到5秒 还不限内存 Orz
设c为gcd(a,b) 而亦或的特性是 满足a^b=c 则 a^c=b。
所以我们可以枚举c 而a是c的倍数 所以可以再枚举a 再算出b=a^c 再检查是否满足 gcd(a,b)==c
而这题还有一个神奇的特性 即 若b满足 axorb=gac(a,b) 则 b一定为 a-gcd(a,b)
这样我们枚举出a,c 的时候 b=a-c 而这时gcd(a,b)是一定为c的 (原因同辗转相减法) 只需验证 是否a^b==c
时间复杂度O(nlogn)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#define scnaf scanf
#define cahr char
#define bug puts("bugbugbug");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod=1000000007;
const int maxn=3e7+10;
const int inf=1e9;
int ans[maxn];
int main()
{
for(int n=1;n<maxn;n++)//n作为因子 即gcd(a,b)
{
for(int i=2;i*n<maxn;i++){
int a=i*n;
int b=a-n;
if( (a^b) == n) {
ans[a]++;
}
}
}
for(int i=1;i<maxn;i++)
ans[i]+=ans[i-1];
int T_T,n,test=1;
scanf("%d",&T_T);
while(T_T--)
{
scanf("%d",&n);
printf("Case %d: %d\n",test++,ans[n]);
}
return 0;
}