UVA - 12716 - 異或序列
阿新 • • 發佈:2018-11-08
求滿足GCD(a,b) = a XOR b; 其中1<=b <=a<=n。
首先做這道題需要知道幾個定理:
異或:a XOR b = c 那麼 a XOR c = b;
那麼我們令GCD(a,b)= c; 這樣 a 是 c 倍數。我們可以通過遍歷c , 然後通過篩法,把c的倍數晒出當作a。求b如何求呢?
書上提供一種方法是利用a XOR c=b 用 gcd(a,b)=c 驗證。但是這個方法是超時的,gcd是logn 級別的 總的時間複雜度,n*(logn)^2。這是我們不能接受的。
還有一種方法是證明b=a-c。這個證明還是不容易的 :
首先gcd(a,b)=c<=a-b 其次要證明a^b>=a-b 但是這是不容易。我們可以這樣想,他們什麼時候取等於,我們知道異或是相同為0,不同為1 那麼 我們把a,b用二進位制展開,這樣我們a,b是每一位對應的,我們把所以不同的二進位制位,全部變為ai = 1,bi = 0。這樣我們知道,沒有借位 那麼a^b == a-b 。那麼後面按照XOR序列的順序變化,a-b變小,那麼a^b>=a-b 從而 c=a-b。命題得證。
證明是否成立,直接用a^b==a-b即可。可以的把,保持在f數組裡面,f[i]代表a=i時的情況數。最後求一個字首和既可以,最後o1查詢即可。
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #define rep(i,j,k) for(int i=j;i<=k;i++) using namespace std; const int maxx=30000001; int f[maxx]; void init(){ for (int i=1;i<=maxx/2;i++){ for (int j=2*i;j<=maxx;j+=i){int b=j-i; if ((j^b)==i){ f[j]++; } } } for (int i=2;i<=maxx;i++){ f[i]+=f[i-1]; } } int main(){ int t; int n; int zz=0; scanf("%d",&t); int cnt=0; int a; memset(f,0,sizeof(f)); init(); while(t--){ zz++; scanf("%d",&n); printf("Case %d: %d\n",zz,f[n]); } return 0; }