hdu多校第四场 1003 (hdu6616) Divide the Stones 机智题

题意:

给你重量分别为1到n的n个石头,让你分成重量相等,数量也相等的k组,保证k是n的约数。问你能不能分配,如果能,输出具体的分配方案。

题解:

首先,如果1到n之和不能整除k,那么一定不能如题意分配。

否则一定能。

设m=n/k。m是每组分到的石头块数。我们把n块石头排成这样m*k的矩阵,假设12块石头,分成3组。

$egin{bmatrix}
(1) & 2 & 3\
(4) & 5 & 6\
7 & 8 & (9)\
10 &11  &(12) 
end{bmatrix}$

每组一定是从每行各拿一个。如果m为偶数,那么,第一个人从前一半的行里拿第一个,后一半的行里拿最后一个,第2个人拿前一半行的第二个,后一半行的倒数第二个,以此类推。

m为奇数的情况就比较难搞,假设15块石头,分成5组

将后两列之和构造成从上到下递增1,然后剩下的奇数个,一行构造成递增,一行构造成递减。

另外,k=1的时候需要特判,比赛最后半小时被卡测评,然后赛后知道因为这个点wa了,心酸。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int M = 1e5 + 5;
int t;
int n, k;
LL sum;
void solve1(int n,int k){
    int tot, cnt;
    tot = n / k;
    cnt = 0;
    printf("yes
");
    for (int i = 1; i <= n / 2; i++)
    {
        printf("%d %d", i, n - i + 1);
        cnt += 2;
        if (cnt == tot)
        {
            printf("
");
            cnt = 0;
        }
        else
        {
            printf(" ");
        }
    }
}
void solve2(int n,int k){
    int tot = n / k;
    int cnt = 0;
    int tot2 = 1+2*k-k/2;
    int tmp = 1;
    printf("yes
");
    for (int i = 1; i <= k; i++){
        for (int j = 1; j <= tot - 2; j++){
            if (j & 1){
                printf("%d ", n - (j - 1)*k - (i - 1));
            }else{
                printf("%d ", n - j * k + 1 + i - 1);
            }
        }
        printf("%d %d
", tmp, tot2 - tmp);
        tot2++;
        tmp += 2;
        if (tmp > k)tmp = 2;
    }
}
int main(){
    scanf("%d", &t);
    while (t--){
        scanf("%d%d", &n, &k);
        sum = (LL)n*(n + 1) / 2;
        if(k==1){
            printf("yes
");
            for(int i=1;i<=n;i++){
                printf("%d ",i);
            }
            printf("
");
        }else if (sum%k){
            printf("no
");
            continue;
        }else{
            if ((n / k) % 2){
                solve2(n,k);
            }else{
                solve1(n,k);
            }
        }
    }
}
原文地址:https://www.cnblogs.com/isakovsky/p/11281662.html