http://codeforces.com/contest...ios
一句話題意:有若干個數字,都是
2的n次冪
;每次取出若干個數字,且要保證取出的數字之和也是2的n次冪
;問至少要取多少次。c++
樣例輸入: 5
1 1 2 3 3
ubuntu
樣例輸出: 2
函數
解:優化
咱們從最簡單的樣例入手。網站
樣例輸入能夠整理以下。x
的後面表示這個數字的出現次數。spa
2^1
x2
2^2
x1
2^3
x2
.net
咱們發現,兩個相同冪次的數,恰好能「等價變換」爲更高次的數。code
2^1
x2
=> 2^2
x1
blog
再加上已有的2^2
,總共有2個2^2
啦。因而,繼續變換,
2^2
x2
=> 2^3
x1
再加上已有的2個2^3
,就有3個2^3
啦。
2^3
x2+1
取出其中兩個進行「變換」,最終結果就是
2^3
x1
2^4
x1
而後,咱們發現無論怎麼操做都沒法進一步組合兩個數進行變換。如今有兩個數,因此答案是2
。
作到這裏,就不難看出其中的規律。二進制
下的「進位」而已。
#include <cstdio> #include<cmath> #include<iostream> using namespace std; int orz[1000000+10000]; int l[] ={1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576}; int search(int n){ for(int i = 0;i<20;i++){ if(l[i+1]>=n){ return i; } } return -1; } int main(){ std::ios::sync_with_stdio(false); std::cin.tie(0); int n,t; scanf("%d", &n); int step = 0; int max = 0; for(int i = 0;i<n;i++){ scanf("%d", &t); max = (t>max?t:max); orz[t]++; } for(int i = 0;i<=max;i++){ if(orz[i] == 0) continue; int now_cnt = orz[i]; int pow; while(now_cnt){ if(now_cnt == 1) step++; now_cnt -= l[pow = log2(now_cnt)]; orz[max=(i+pow>max?i+pow:max),i+pow]++; } } printf("%d\n", step); return 0; }
其中兩行,
std::ios::sync_with_stdio(false); std::cin.tie(0);
就是所謂的iostream
優化。
第一行的原理就是解除iostream
和stdio
的綁定。
第二行的原理是解除cin
與cout
的綁定。
詳情請看這篇文章。
爲啥要優化呢?由於我起初作這題是用的51nod(這個網站提供這題的中文題目)的機器很是辣雞,就是卡I/O。瘋狂TLE。
我試了能AC的兩種方法,第一種是刪除全部c++
特性語句,使用printf
與scanf
,用c
來提交;第二種就是所述的iostream
優化。
題外話:
有些時候,本身重寫printf
和scanf
效率更高。
由於getchar
和putchar
函數很快。
從qscqesze的島娘模版上摘抄以下:
template<class T> inline T& RD(T &x){ //cin >> x; //scanf("%d", &x); char c; for (c = getchar(); c < '0'; c = getchar()); x = c - '0'; for (c = getchar(); '0' <= c && c <= '9'; c = getchar()) x = x * 10 + c - '0'; //char c; c = getchar(); x = c - '0'; for (c = getchar(); c >= '0'; c = getchar()) x = x * 10 + c - '0'; return x; } int ____Case; template<class T> inline void OT(const T &x){ //if (x == -1) printf("Case %d: NO\n", ++____Case); //else printf("Case %d: %d\n", ++____Case, x); //printf("%I64d\n", x); //printf("%.2lf\n", x); printf("%d\n", x); //cout << x << endl; }
這至關於重寫了scanf
。
至於用putchar
重寫printf
……之後再說吧,由於不多遇到大量輸出的狀況。