robin哥哥:資料範圍小的數是題目的突破點
阿新 • • 發佈:2018-12-09
XOR Clique
題目:
寶寶現在有一個序列a1,a2……an,它想找一個子序列S,使得子序列裡面的任意兩個數異或之後小於兩數的最小值,且該子序列要最長,輸出最長子序列長度
分析:兩數異或,同數位如果相同則為0,不同則為1,一個十進位制的數轉換為二進位制數之後最高位一定為1,如果兩個十進位制數轉換為二進位制數之後長度相同,那麼最高位異或之後就會是0,所以要想實現子序列中任意兩數異或之後小於兩數最小的那個,就要保證子序列中所有數轉換為二進位制數之後長度相同。那麼問題就變為:把序列中每個數轉換成二進位制數的長度存到雜湊表,再在雜湊表中找最大值,即為最長子序列。
#include <bits/stdc++.h> using namespace std; int a[100005]; int main() { int power[33],t,i,n; scanf("%d",&t); while(t--) { memset(power,0,sizeof(power));//別忘了每個case清空雜湊表 scanf("%d",&n); for(i=0; i<n; i++) { scanf("%d",&a[i]); power[(int)log2(a[i])+1]++;//計算每個數轉換為二進位制數的長度,並存到雜湊表裡 } int maxn=0;//別忘了每次都要令maxn歸零 for(i=0; i<=32; i++) { maxn = max(maxn,power[i]);//找最長子序列 } printf("%d\n",maxn); } }
Coins and Queries
題目:
Polycarp有n個硬幣,第i個硬幣的價值是ai。 保證所有值都是2的整數冪(即對於某些非負整數d,ai = 2^d)。
Polycarp希望知道q查詢的答案。 第j個查詢被描述為整數bj。 查詢的答案是使用某些硬幣子集獲得值bj所需的最小硬幣數量(Polycarp只能使用他擁有的硬幣)。 如果Polycarp無法獲得值bj,則第j個查詢的答案為-1。
查詢是獨立的(查詢的答案不影響Polycarp的硬幣)。
分析:題目中說硬幣的面值都是2 ^ d(d為非負數),又知道任何一個2 ^ d的數都可以由2的更低次冪相加得到,那麼很明顯暗示我們要把每枚硬幣的d算出來,放進數位雜湊表,然後從最高次冪開始貪心算下來,如果最後查詢數值可以變為0,則說明能湊出這個數,反之,則不能。
#include <cstdio> #include <algorithm> #include <cmath> using namespace std; int main() { int n,q,i,a,power[32]={0},c,j,k,b; scanf("%d%d",&n,&q); for(i=0; i<n; i++) { scanf("%d",&a); power[int(log2(a)]++;//把每枚硬幣的d算出來,存進雜湊表 } for(i=0; i<q; i++) { scanf("%d",&b); c = 0;//計數器 for(j=31; j>=0; j--)//硬幣最大面值不會超過2^31次方,所以從31開始列舉 { k = min(power[j],b/(1<<j));//1<<j表示2^j,k是應該拿出該面值的硬幣的個數,理想是有多少拿多少,但是有可能b並沒有那麼大,所以k=min(該面值硬幣個數,最大能容納的個數) c += k; b -= k*(1<<j);//一共拿了多少錢,總數就得減去多少 } if(b != 0)//當硬幣面值都列舉完,發現b還是沒能為0,那麼就說明這堆硬幣湊不出b數值的數 printf("-1"); else printf("%d",c); printf("\n"); } }