• GCD=XOR问题(UVA 12716 阉割版)


    GCD=XOR问题

    问题

    给定一个n, 问求出(a,b)无序数对, 使a^b=gcd(a, b)

    题解

    数学证明

    设a>=b, a^b=c

    因为^的规则是, 只有两个数的同一位有一个0和一个1时, 结果才为1, 否则都是0.

    这样对于a, b, c的每一位的真假, 只可能出现两种情况: 0,0,0和0,1,1. 而这两种情况都是对于a, b, c知二推一.

    所以,若 a^b=c, 则 a^c=b, b^c=a.

    当a-b的时候, 分类讨论每一位:

    某位上, 0-0=0, 这时c的这一位也是0

    1-1=0, 这时c的这一位是0

    1-0=1,c的这一位是1

    0-1=-1,借位,这时c的这一位是1.

    所以, 前三种情况结果都是a^b=a-b

    只有最后一种情况a^b>a-b.

    所以a^b>=a-b.

    而且, 又因为c=gcd(a, b)<=a-b (显而易见, 否则a/c, b/c就有可能是分数)

    题目规定的c=gcd(a, b)=a^b

    c=a-b=a^b就是它的必要条件

    设计算法

    接下来, 只要保证a-b>c就可以求出所有结果了.

    因为a不能等于b, 因为这时gcd(a, b)=a=b, a-b=0

    所以a至少比b大c.

    又因为b至少是c的一倍

    所以a必须是两倍起跳.

    又因为a<=n, a>=b+c>=2c.

    所以c必须小于等于n/2.

    因为a xor b=c, a xor c=b, b xor c=a, 知一推二

    a-b=c, a-c=b, 知一推一

    所以只要a^c=a-c

    就满足a^b=a-b

    这样就保证了在这个范围内的a, c, 只要满足a^c=a-c, 答案就成立.

    #include<iostream>
    #include<cstdio>
    using namespace std;
    long long N, Ans = 0;
    int main()
    {
    	cin >> N;//设b<a
    	for (register int i = 1; i <= N >> 1; i++) {//这个地方枚举的是gcd, 因为gcd一定小于b, 并且gcd=a^b=a-b, 所以gcd一定小于a/2(也就是N/2), 这样gcd就一定小于b了
    		for (register int j = i << 1; j <= N; j += i) {//根据gcd枚举a, 因为是倍数关系, 所以增量为gcd, 而且a>b且b最小就是gcd的一倍, 所以a是两倍起跳
    			if ((i ^ j) == j - i) {//符合必要条件
    				Ans++;
    			}
    		}
    	}
    	cout << Ans << endl;//其实只有一个数字不用printf.
    	return 0;
    }
    
  • 相关阅读:
    2019牛客多校第二场H题(悬线法)
    hdu6212 Zuma(区间dp)
    uva1428树状数组
    UVA1395 (最苗条的最小生成树)
    牛客练习赛53 C题bitset
    Love Live!
    Princess principal
    New Game!- 牛客
    P3311 [SDOI2014]数数
    [HNOI2008]GT考试
  • 原文地址:https://www.cnblogs.com/Wild-Donkey/p/12629341.html
Copyright © 2020-2023  润新知