Divide the Stones(HDU-6616)

Problem Description

There are n stones numbered from 1 to n.
The weight of the i-th stone is i kilograms. We divide the stones into k groups.
Each group consists of exactly stones.
We define the weight of each group is sum of the stones’ weights in the group.
Can we divide the stones so that the weights of all groups are same?

Input

The first line of input contains an integer T (1 <= T <= 100) denoting the number of test cases.
Each test case consists of one line containing two integers n (1 ≤ n ≤ 100000), k (k is divisor of n).
It is guaranteed that the sum of n overall test cases does not exceed 500000.

Output

For each test case, if you can’t divide into k groups satisfying condition, print “no”.
Else if you can divide into k groups satisfying condition, print “yes” in one line and then print k lines.
The i-th line represent the indices of stones belonging to the i-th group.
If there are multiple solutions, you can print any of them.

Sample Input

1
4 2

Sample Output

yes
1 4
2 3

题意:t 组数据,每组给出 n、k 两个数,代表有 n 个重量从 1~n 的石头,现在要将这些石头分成 k 堆,使得每堆的重量与数量相等,问能否分配,若能,输出 yes 与对应方案,若不能则输出 no,题目保证 k 是 n 的约数

思路:

首先,对于 1 到 n 的和 \frac{n(n+1)}{2} 如果不能整除 k,那么一定不能分配

然后再考虑 \frac{n}{k},当其为偶数时,每一堆的个数为偶数,重量为 \frac{\frac{n(n+1)}{2}}{k},那么可以用 \frac{\frac{n}{k}}{2} 个和为 n+1 的数对组成

当其为奇数时,我们将前 3k 个石头分成等重量与等数量的 k 堆,即每堆 3 个,重量为 \frac{9k+3}{2},之后再将剩下的 n-3k 个石头成对进行分配

而将前 3k 个石头分成 k 堆,分法有多种,比较简单的一种是:

  • 若 i 为奇数:i,\frac{3k+2}{2}-\frac{i}{2},\frac{6k+1}{2}-\frac{i}{2}
  • 若 i 为偶数:i,\frac{4k+2}{2}-\frac{i}{2},\frac{5k+1}{2}-\frac{i}{2}

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<unordered_map>
#include<bitset>
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<int,int>
LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; }
LL multMod(LL a,LL b,LL mod){ a%=mod; b%=mod; LL res=0; while(b){if(b&1)res=(res+a)%mod; a=(a<<=1)%mod; b>>=1; } return res%mod;}
LL quickPowMod(LL a, LL b,LL mod){ LL res=1,k=a; while(b){if((b&1))res=multMod(res,k,mod)%mod; k=multMod(k,k,mod)%mod; b>>=1;} return res%mod;}
LL getInv(LL a,LL mod){ return quickPowMod(a,mod-2,mod); }
LL GCD(LL x,LL y){ return !y?x:GCD(y,x%y); }
LL LCM(LL x,LL y){ return x/GCD(x,y)*y; }
const double EPS = 1E-10;
const int MOD = 998244353;
const int N = 200000+5;
const int dx[] = {-1,1,0,0,1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n, k;
        scanf("%d%d", &n, &k);
        LL sum = 1LL * n * (n + 1) / 2;
        if (sum % k != 0)
            printf("no\n");
        else {
            printf("yes\n");
            if (k == 1) { // k=1时特判
                for (int i = 1; i <= n; i++)
                    printf("%d ", i);
                printf("\n");
            } else {
                if ((n / k) % 2 == 0) { // n/k为偶数
                    int temp = k;
                    int i = 1;
                    while (temp--) {
                        for (int j = 1; j <= n / k / 2; j++)
                            printf("%d %d ", i++, n + 1 - i);
                        printf("\n");
                    }
                } else { // n/k为奇数
                    int i = 1, j = 3 * k + 1, temp = k;
                    while (temp--) {
                        //前k堆
                        if (i % 2)
                            printf("%d %d %d ", i++, (3 * k + 1) / 2 - i / 2, (6 * k + 1) / 2 - i / 2);
                        else
                            printf("%d %d %d ", i++, (4 * k + 2) / 2 - i / 2, (5 * k + 1) / 2 - i / 2);
                        //剩余的n-3k个
                        for (int i = 1; i <= (n / k - 3) / 2; i++)
                            printf("%d %d ", j++, 3 * k + 1 + n - j);
                        printf("\n");
                    }
                }
            }
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值