題目鏈接:jzoj 1747
題目
有堆石子,從編號,其石子總數爲。每次可以選擇兩堆石子和,滿足堆的石子數不比堆的多,記爲的石子數。然後可以進行以下操作:從堆石子中拿這麼多的石子到堆中。要求你給出一個方案,使得最後有一堆石子的數目達到。
輸入
第一行兩個正整數,。
第二行個非負數。
輸出
輸出若干行,每行兩個數,,表示每次操作中的兩堆石子的編號,必須滿足題中所給的大小關係!
樣例輸入
2 2
3 1
樣例輸出
2 1
1 2
數據範圍
對於的數據,;
對於的數據,,。
思路
這道題是一道暴力。
我們要讓其中一個數變爲,其實就是然其它數都爲。
那麼,我們可以枚舉從低到高每一位,把這一位不爲零的數成對的進行操作。因爲經過操作之後,這兩個數的這一位都會變成零。(判斷這個數某一位是否爲可以用位運算解決)
然後就可以了。
代碼
#include<cstdio>
using namespace std;
int n, k, a[100001], t;
int main() {
scanf("%d %d", &n, &k);//讀入
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);//讀入
for (int i = 1; i <= k; i++)
for (int j = 1; j <= n; j++)
if (a[j] & (1 << (i - 1))) {//這一位還是1
if (!t) t = j;//沒有找到另一半
else {
if (a[t] < a[j]) {//左邊的比右邊大
printf("%d %d\n", t, j);
a[j] -= a[t];
a[t] *= 2;
t = 0;
}
else {//右邊的比左邊大或者一樣大
printf("%d %d\n", j, t);
a[t] -= a[j];
a[j] *= 2;
t = 0;
}
}
}
return 0;
}