Mathematics
jzoj 1747
题目大意
有n堆石子,总和为 2 k 2^k 2k,现在对于两堆石子,你可以从a中取b的分量到b(a要大于b),问合成一堆大小为 2 k 2^k 2k的石子要怎么做(输出a,b)
输入样例
2 2
3 1
输出样例
2 1
1 2
数据范围
对于30%的数据,n=2;
对于100%的数据,
n
⩽
100000
,
k
⩽
31
。
n\leqslant 100000,k\leqslant31。
n⩽100000,k⩽31。
解题思路
既然总和就是最后一堆的大小那就是把所有合在一起啦
我们从小到大枚举二进制下的每一位,如果有1的那就找另一个有1的和他调一下,这样就可以清掉一位,我们不停清,最后就只剩
2
k
2^k
2k了
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll n, k, p, s, a[100500];
int main()
{
scanf("%lld %lld", &n, &k);
for (ll i = 1; i <= n; ++i)
scanf("%lld", &a[i]);
for (ll sum = 1, i = 0; i < k; ++i, sum <<= 1)//每一位
for (ll j = 1; j <= n; ++j)
if (a[j]&sum)
{
if (!p)//没有前面一个先记录下来
s = j, p = 1;
else
{
if (a[j] > a[s])//有前面一个就要判断谁给谁
{
a[j] -= a[s];//给他那么多就减掉那么多
a[s] <<= 1;//乘上2
printf("%lld %lld\n", s, j);
}
else
{
a[s] -=a[j];
a[j] <<= 1;
printf("%lld %lld\n", j, s);
}
p = 0;
}
}
return 0;
}