Uva 12716 GCD XOR

24 篇文章 0 订阅
22 篇文章 0 订阅

题目

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=49096

题解

这道题开始完全懵逼,只知道n^2乱搞。(看着xor我表示有心理压力,SCOI2016后遗症,而且我不会告诉你我开始是奔着把所有的数对求出来的心理做的。)然后手玩数据,发现(2k,2k+1)肯定是一组,这就有floor((n-1)/2)这么多的组数了,然后打表去看gcd(a,b)==a xor b=k(2<=k<=100)的数对,然而并没有什么卵用。我甚至忽略了a-b==gcd(a,b)这个重要的东西。


正题:xor有个神奇的性质
if a xor b==c __ ==>a xor c==b
又因为c是a的约数,所以枚举a,c的复杂度一共是nlogn
插一句,为什么是nlogn?本蒟蒻想的是枚举a然后sqrt(a)枚举约数,然而实际上是先枚举c,再for(int a=c*2;a<=30000000;a+=c) ,(我智商确实低),所以这就和筛素数一样了,nlogn(其实c只到30000000/2即可,常数小)
a,c知道了,则b=a xor c,若gcd(a,b)==c,则成立。gcd的复杂度。。我只知道很小,刘汝佳说是logn(感觉也够小了),那么整个时间复杂度就是O(n(logn)^2).(讲道理我觉得也许能卡着过?)
拓展:打表之后我发现gcd(a,b)==a-b;所以c==a-b,所以b=a-c;这时gcd(a,b)一定为c,简易证明:
设a=a’ * c;
则b=a+c=(a’ +1)*c;
因为gcd(a’,a’+1)==1;
所以gcd(a,b)==c;
所以gcd那个log就去掉了,而且完全不用写gcd(虽然也就一两行)。


我觉得我要是没有想到像筛法一样的枚举顺序,想到了所有的点也做不出来。智商感人。

代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=30000000+10;

int ans[maxn],cnt[maxn];

inline int read()
{
    int ret=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
    return ret;
}

int main()
{
    int n=30000000;
    for(int c=1;c<=n/2;c++)
        for(int a=c<<1;a<=n;a+=c)
        {
            int b=a-c;
            if(c==(a xor b)) cnt[a]++;
        }
    for(int i=1;i<=n;i++) ans[i]=ans[i-1]+cnt[i];
    int T,k,kase=0;cin>>T;
    while(T--)
    {
        k=read();
        printf("Case %d: %d\n",++kase,ans[k]);
    }
    return 0;

}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值