JZOJ4714公约数
2016-08-19 20:51
190 查看
题目描述
给定一个正整数,在[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性质不够熟悉,导致想了很久很久,才试了出来。
其实还有些隐藏属性,比赛的时候时间不够不管了。
所以对题目的条件或满足的性质,要清晰地以式子表达,理清关系,这样想算法才会快。
相关文章推荐
- 【JZOJ4714】公约数
- JZOJ.4714【NOIP2016提高A组模拟8.19】公约数
- JZOJ 4714 公约数
- JZOJ 4714 【NOIP2016提高A组模拟8.19】公约数
- Jzoj4714 公约数
- 【JZOJ 4714】 公约数
- 【挖坑记】JZOJ 4714 公约数
- 【jzoj4714】【公约数】【数论】
- [JZOJ 4714]【NOIP2016提高A组模拟8.19】公约数
- JZOJ4714公约数 找规律
- 【JZOJ 4714】公约数
- BZOJ 3669 . JZOJ 3754. 【NOI2014】魔法森林
- JZOJ 5489. 【清华集训2017模拟11.28】海明距离
- jzoj【NOIP2017提高A组集训10.28】图
- jzoj3501 【NOIP2013模拟联考15】消息传递(news) 树形dp
- jzoj3577 [CEOI2011]Traffic 强连通分量缩点
- jzoj 3583. 【GDOI2014模拟】小A的树
- JZOJ4899. 【NOIP2016提高A组集训第17场11.16】雪之国度
- Jzoj4348 打击目标
- JZOJ 3648. 【GDOI2014】beyond