Mathematics(jzoj 1747)

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。 n100000k31

解题思路

既然总和就是最后一堆的大小那就是把所有合在一起啦
我们从小到大枚举二进制下的每一位,如果有1的那就找另一个有1的和他调一下,这样就可以清掉一位,我们不停清,最后就只剩 2 k 2^k 2k

代码

#include
#include
#include
#include
#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;
}

你可能感兴趣的:(其他算法)