题意:
给你重量分别为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); } } } }