P315 GCD等于XOR UVa12176 “不难发现”的解释 以及完整推导过程

1. a-b<=a xor b,

对于在同一个数位相同的二进制位值,xor和减法的效果都是一样的。

对于在同一个数位不同的二进制位值,xor恒等于1,而减法可能向高位借1.

2.gcd(a,b)<=a-b (假设a>b)

因为gcd(a,b)=gcd(b,a%b)

设a=qb+r  r=a%b=a-qb

gcd(b,a%b)=gcd(b,a-qb)

此时最大公因数不会超过a-qb

而a-qb<=a-b

所以gcd(a,b)=gcd(b,a%b)<=a-b

——————心累的分割线——————很明显吗——————
完整的思路总结
 

设 c=a^b=gcd(a,b)
发现 c=a-b
证明该结论成立


对于c=a^b>=a-b,
对于在同一个数位相同的二进制位值,xor和减法的效果都是一样的。
对于在同一个数位不同的二进制位值,xor恒等于1,而减法可能向高位借1.


对于c=gcd(a,b)<=a-b (假设a>b)
因为gcd(a,b)=gcd(b,a%b)
设a=qb+r  r=a%b=a-qb
gcd(b,a%b)=gcd(b,a-qb)
此时最大公因数不会超过a-qb
而a-qb<=a-b
所以gcd(a,b)=gcd(b,a%b)<=a-b


故满足上述条件的c==a-b

有gcd这一层的关系在
可以让a成为c的倍数来筛选
又使用c=a-b的关系,设a=nc,
则gcd(a,b)=gcd(a,a-c)=gcd(nc,(n-1)c)=c ——因为n与n-1互质
所以接下来只需要验证a^b==c即可

有一点不知你们注意到没,cnt++的位置是a——默认的较大的数
因为a,b均应当满足小于等于n的条件,所以应当记在a的位置

 

/*SE:wn------王宁*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 30000000+1;
int cnt[maxn];
int sum[maxn]; 
int main()
{
	int i,j,n,runs,run,a,b,c;
	memset(cnt,0,sizeof(cnt)); memset(sum,0,sizeof(sum));
	/*总结:利用约数的性质实现筛法
	第一种做法使用了
	1.打印结果找规律 2.利用数学证明该规律成立
	该规律是:如果gcd(a,b)==a^b,那么c=a-b
	3.知晓规律后我们使用c=a-b来推导b
	那么这个b=a-c背后的含义是什么呢?
	书上是说gcd(a,b)=gcd(a,a-c)=c
	所以这个b=a-c明面上确认了gcd(a,b)==c这个条件
	为c==a^b的成立提供了可能
	小结:要使条件成立,b必须等于a-c
	有了这个前提后,gcd部分一定成立*/
	for(c=1;c<=15000000;c++)
		for(a=c*2;a<=30000000;a+=c)
		{
			b=a-c;
			if(c==(a^b)) ++cnt[a]; //1080ms
			/*b=a^c;
			if(b%c==0&&b<a) ++cnt[a];//1950ms
			这个也能用但是我不会证明*/
		}
	for(i=1;i<=30000000;i++) sum[i]=sum[i-1]+cnt[i];
	scanf("%d",&runs);
	for(run=1;run<=runs;++run)
	{
		scanf("%d",&n);
		printf("Case %d: %d\n",run,sum[n]);	
	} 
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值