YY 的 GCD

题目背景
是一个热爱学习的奆佬,他尤其喜欢 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\n",i,ans[n]);
    }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/gshdyjz/p/9877040.html
今日推荐