UVA.12716 GCD XOR (暴力枚举 数论GCD)

来源:互联网 发布:mac卸载软件 编辑:程序博客网 时间:2024/06/08 04:04

UVA.12716 GCD XOR (暴力枚举 数论GCD)

题意分析

题意比较简单,求[1,n]范围内的整数队a,b(a<=b)的个数,使得 gcd(a,b) = a XOR b.

前置技能

XOR的性质
GCD

由于题目只给出一个n,我们要求对数,能做的也始终暴力枚举a,b,这样就有n^2的复杂度,由于n很大,根本过不了。

于是我们就想用到其中一些性质,如XOR 与GCD,不妨假设 a xor b = c,并且根据题意还知道, gcd(a,b) = c,也就说明c一定是a的因子,所以在枚举的时候,可以转过头来枚举a和c.那么如何求出当前情况下的b呢,考虑到xor的性质,即 a xor b = c, a xor c = a xor a xor b = b. 通过异或运算就可以求解出来b,然后再检验gcd(a,b)是否为c即可。

到这里其实已经足够了,但是打出一定规模符合题意的(a,b,c),不难发现,a-b=c,有了这条性质,就可以不用gcd检验了。换句话说,通过枚举a,c,b = a-c计算出b,通过a^b=c检验是否符合条件。因为相对而言,位运算比gcd快得多。

值得一提的是,由于n很大,连续处理多个n很大的值的时候,速度表现不能令人满意,最先想到的办法就是打表方法。

代码总览

#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#define nmax 30000010#define ll long longusing namespace std;int n;int t;int num[nmax];void init(){    for(int c = 1;c<=(nmax+1)/2;++c){        for(int a = c+c;a<nmax;a+=c){            int b = a-c;            if((a^b) == c) num[a]++;        }    }    for(int i = 2;i<nmax;++i)  num[i]+=num[i-1];}int main(){    int kase =1 ;    init();    scanf("%d",&t);    for(kase  = 1; kase <=t;++kase){        scanf("%d",&n);        printf("Case %d: %d\n",kase,num[n]);    }    return 0;}
原创粉丝点击