Mathematics
发布日期:2021-05-07 06:55:13 浏览次数:29 分类:精选文章

本文共 1355 字,大约阅读时间需要 4 分钟。

M a t h e m a t i c s Mathematics Mathematics

题目链接:

题目

n n n堆石子,从 1 ∼ n 1\sim n 1n编号,其石子总数为 2 k 2^k 2k

每次可以选择两堆石子 a a a b b b,满足 a a a堆的石子数不比 b b b堆的多,记 c c c a a a的石子数。然后可以进行以下操作:从 b b b堆石子中拿 c c c这么多的石子到 a a a堆中。

要求你给出一个方案,使得最后有一堆石子的数目达到 2 k 2^k 2k

输入

第一行两个正整数 n n n k k k

第二行 n n n个非负数 a i a_i ai

输出

输出若干行,每行两个数 a a a , b b b,表示每次操作中的两堆石子的编号,必须满足题中所给的大小关系!

样例输入

2 23 1

样例输出

2 23 1

数据范围

对于 30 % 30\% 30%的数据, n  ⁣ =  ⁣ 2 n\!=\!2 n=2

对于 100 % 100\% 100%的数据, n  ⁣ <  ⁣ =  ⁣ 100000 n\!<\!=\!100000 n<=100000 k  ⁣ <  ⁣ =  ⁣ 31 k\!<\!=\!31 k<=31

思路

这道题就是暴力,很暴力。

因为每一次操作就会是石子多的给石子少的,让石子少的加一倍。

而且它没有说要用最快的方法,那我们就可以慢慢来。
我们可以直接从小到大枚举位数,因为石子总和加起来一定是 2 k 2^k 2k,所以我们如果一位一位的处理,那么我们每一位枚举完之后,那一位所有的数一定都是 0 0 0,所以接下来往高位枚举无论怎么放石子,之前的位数都会是 0 0 0
所以我们就可以用这种方法,得出答案。

代码

#include
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;//之前这一位都全部是0了 else { //之前的数还有是1的,可以操作 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;}
上一篇:PPMM
下一篇:Why Did the Cow Cross the Road I P

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2025年03月22日 15时40分23秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章