1. 程式人生 > >UVA12716 GCD XOR

UVA12716 GCD XOR

題意翻譯

輸入資料組數t,接下來t行每行給定一個數字n,如樣例所示格式輸出滿足1<=b<=a<=n且gcd(a,b)==a xor b的(a,b)二元組個數。

translated by @AdzearDisjudge

題目描述

PDF

輸入輸出格式

輸入格式:

 

 

輸出格式:

 

 

輸入輸出樣例

輸入樣例#1: 
2
7
20000000
輸出樣例#1: 
Case 1: 4
Case 2: 34866117

 

Solution:

  (又來補上部落格…)本題應該是一次模擬考試的原題,思路很簡單的數學。

  我們假設$a>b$,不難得出結論:1、$a\;xor\; b\geq a-b$  2、$gcd(a,b)\leq a-b$。

  先證明結論1:簡單點說吧,異或操作可以看成憑空借位直接相減的減法(這裡預設較大的數為被減數),比如說某位的運算為$0\;xor\;1$,並不需要向前一位借$1$而是直接將$0$加上$2$再減$1$得到運算結果為$1$。那麼貪心的想到,$a\;xor\;b$的值一定會大於等於$a-b$的值,因為$a-b$運算時若某位不夠減是向前一位借$1$而不是憑空借到$1$,或者理解成異或操作在某位不夠減時被減數的該位憑空加上$2$,假設一次異或操作各數位上憑空借了的值的和為$c,c\geq 0$,顯然就有$a+c-b\geq a-b$成立了。

  再證明結論2:我們由歐幾里得演算法可知,$gcd(a,b)=gcd(b,a-b)$(該證明過於簡單不需贅述),那麼顯然$a>b$時$gcd(a,b)\leq a-b$成立。

  於是我們可以直接夾逼,設滿足條件的$gcd(a,b)=a\;xor\;b=x$,則有$a-b\leq x\leq a-b$,那麼顯然$x=a-b$。

  所以本題演算法就出來了:考慮用字首和統計方案數,直接$1\rightarrow n$列舉每個最大公約數$x$,然後判斷相鄰的兩個$x$的倍數異或值是否為$x$,成立就字首+1。

  時間複雜度調和級數+詢問T:$O(n\log n+T)$

程式碼:

 

/*Code by 520 -- 10.30*/
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=3e7+5;
int s[N],T;

int gi(){
    int a=0;char x=getchar();
    while(x<'0'||x>'9') x=getchar();
    while(x>='0'&&x<='9') a=(a<<3)+(a<<1)+(x^48),x=getchar();
    return a;
}

int main(){
    For(g,1,N-1){
        for(RE int a=(g<<1),b=g;a<N;a+=g,b+=g) if((a^b)==g) s[a]++;
        s[g]+=s[g-1];
    }
    T=gi();
    For(i,1,T) printf("Case %d: %d\n",i,s[gi()]);
    return 0;
}