JZOJ4714公约数

题目描述

给定一个正整数,在[1,n]的范围内,求出有多少个无序数对(a,b)满足gcd(a,b)=a xor b。
对于30%的数据满足n<=1000
对于60%的数据满足n<=10^5
对于100%的数据满足n<=10^7

分析

30分:暴力枚举两个数直接判断;
有点难以下手,那么我们看到GCD可以想到先把GCD确定,再考虑。于是设GCD为c,那么我们现在要找的就是a xor b=c的方案数了。我们可以枚举a=i*c,b=j*c再判断gcd(a,b) 与 a xor b是否等于c。
这样似乎多此一举了,再看看如何优化?我们知道:若a xor b=c ,则a xor c=b,这样我们就可以不用枚举b了,因为b已经被a,c所确定,直接判断gcd就可以。那么时间复杂度降至 O(Nlog2N)
其实根本不必求gcd(a,b)。从二进制角度考虑xor:我们先把a,b,c看做二进制数,设a>b,可以发现:a最多只能被b改变b这么多,就是说b的所有位都跟a对应的一样。
那么gcd(a,b)≤a-b,a xor b≥a-b
明显:a-b=c。
整理一下:有三个条件,
1,gcd(a,b)=c
2, a xor b=c
3, a-b=c
其中满足1,2,3就随之满足。

我们枚举的a是c的倍数,那么b满足3就能满足1:
gcd(i*c,i*c+1)=gcd(i,i+1)*c=1*c。
那么我们剩下的只是2了。
所以我们枚举c和a,则b=a-c。判断条件2即可。
nlogn解决。常数很小可以过。

代码

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
long long ans;
int n,x,i,j,l,r,le,ri;
int main()
{
    ans=0;
    scanf("%d",&n);
    fo(i,1,n)
    {
        fo(j,1,n/i-1)
        {
            if (((i*j)^(i*j+i))==i)
                ans++;
        }
    }
    printf("%lld\n",ans);
}

反思

比赛的时候这道题想了很久,写博客也是断断续续的,究其原因是逻辑不清,数学思维不清晰。数学题如果没有太了解相关的性质,就需要去做猜想,证明然后理清楚性质,与各种约束关系。最后寻找可行方法。
比如这题我很快能推出3个条件,但是不能把它们表达清楚更理不好关系,不存在清晰逻辑,而且对gcd性质不够熟悉,导致想了很久很久,才试了出来。
其实还有些隐藏属性,比赛的时候时间不够不管了。
所以对题目的条件或满足的性质,要清晰地以式子表达,理清关系,这样想算法才会快。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值