标签:lvg bom AAT srx div vss aws apm epp
首先我们看到这一道题,聪明的你一定发现了第10个点:n<=20000000。
但是,先不要慌,我们先来证一个不等式:
证明:x ^ y >= x - y >= gcd( x , y )。(其中‘^’代表异或)
我们先来证明左边。
从上面那一张异或与减运算的竖式中可以看出:
其实"^"和"-"运算唯一不同的地方仅仅在于运算方法上的不同。
所以我们不妨将上图中所有的数都转化成二进制。
于是就有:
这时候我们注意一下下图中圈了红圈的地方:
我们可以发现:当a=0,b=1时,a异或b=1,而a-b=-1(图中具体表现为退位)。
为了让你更好的理解,下面请看一张分析表:
所以,我们可知,对于两个数的对应的每一位a,b,均有:
a xor b >= a - b 。(xor表示异或)
所以 x xor y >= x - y ,当且仅当x与y的对应二进制位不为0和1时,等号成立。
原式左边得证。
下面我们再看到右边:x - y >= gcd( x , y )。
根据更相减损术:gcd( x , y )=gcd( y , x-y ),( x > y )
所以原式等价于x - y >=gcd( y , x-y )。
又因为b = gcd( a , b ) * k (k >= 1),
所以x - y >=gcd( y , x-y )这个式子显然成立。
原式右边得证。
所以原式得证。
现在我们回到原题,题目的条件为:
i xor j = gcd( i , j )。
我们将它带人那个不等式中,可得:
i xor j = i - j = gcd( i , j )。
也就是说,i - j = i xor j。
所以我们只要枚举i与i xor j就行了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,sum; 4 int main() 5 { 6 cin>>n; 7 for(int c=1;c<=n;c++)//枚举a-b(同时也是gcd(a,b)) 8 for(int a=2*c;a<=n;a+=c)//因为a>=b,所以从a=2*c开始枚举 9 if(c==(a ^ a-c))sum++;//如果 c=a^b(b=a-c),答案++ 10 printf("%d",sum);//输出答案 11 return 0; 12 }
可是,n<=20000000啊!
没事,不慌。
相信我。
你们知道微积分吗?
如果不知道,我现场告诉你一个公式:
n/1+n/2+n/3+……+n/n=logen (因为本人是初中蒟蒻,所以只知道有这东西)
你知道这意味着什么吗?
我们的程序的时间复杂度其实是nlogen=nlogn!
所以……可以AC!
(本人的温馨提示:建议大家最好像上面的代码一样,不然会被卡常!)
标签:lvg bom AAT srx div vss aws apm epp
原文地址:https://www.cnblogs.com/xinxiyuan/p/11327973.html