CSUSTOJ-小樱的库洛牌(恶心的构造题)

题目连接:http://acm.csust.edu.cn/problem/4020
CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/109541023

Description

众所周知,木之本樱有 \(n\) 张库洛牌,每张库洛牌按危险程度可以分成等级 \(1-n\) ,由于所有库洛牌都放在一起的太危险了,所以小樱想把 \(n\) 张库洛牌等分成 \(k\) 组,让每组危险程度的和的最大值和最小值的差值最小 ,但由于木之本樱只是友枝小学的学生,实在不知道该怎么分,于是她找到了聪明的 \(ACMer\)

input

第一行三个整数 \(n, k\) , \((1 \leq n \leq 1e5)\) , \((1 \leq k \leq n)\) ,并且保证 \(n\) 可以整除 \(k\)

output

输出 \(k\) 行,每行 \(\frac{n}{k}\) 个整数 (可以输出任意一组解)

Sample Input 1
4 2
Sample Output 1
1 4
2 3

这是个恶心的找规律和构造题目。。。我们设\(len=\frac{n}{k}\),即每组数的个数。很明显当\(len\%2==0\)的时候我们一定可以构造出\(1-n,2-(n-1)...\)这样两两相等的\(\frac{n}{2}\)个组合可以平均分配给每组。

接下来当\(len\)为奇数的时候才是重头戏,对于这种情况我们如果没有什么想法的话只能竟可能地去寻找规律。说实话我找了1个多小时才有意识地找到了QAQ。。。

我们可以发现的一个规律就是对于\(len\)为奇数而言,它分为2种情况,一个就是当\(k\)为偶数的时候,它的最小差值一定会是1,当\(k\)为奇数的时候他的最小差值是0。

那么我们现在就需要考虑怎么分配的问题了,很明显我们可以提出一个偶数的长度来减小工作量,那么我们肯定不能提出\(len-1\)这个偶数,因为这样的话就导致了最小差值为\(k-1\)

那么我们可以考虑提出\(len-3\)这个偶数,那么前面的3个数就可以得到及时的调整,但我们目前所担心的就是前三个数的调整是否能够得到最优结果。事实上我们可以通过实验来验证的。我们将这个n个数分为\((1,2,3...,k),(1,2,3...,k)...\)这样的\(n/k\)组,然后我们就可以对于k组从这些组中每组挑选一个(这样的话由于每组有个基础值,所以我们可以都从1到k)这句话有点可能有点绕,但却是这题的最关键的地方。比如拿15 5举例,我们可以画出如下的匹配图形:
在这里插入图片描述
也就是得到了\((1,3+5,5+10)(2,4+5,3+10)(3,5+5,1+10)(4,1+5,4+10)(5,2+5,2+10)\)这样的构造,我们可以算出他们每组的值都是一样的,所以可以得到最小差值为0。那么按照上面的规律,我们按顺序一个一个往下走就完事了,第一列是往下走的,第二列是从中间开始往下走然后如果超出边界了则直接到1继续往下走也就相当于首位相接了,对于第三列则是从n往上走的,走的步长为2,也是相当于首位相接了。

接下来当这个\(k\)为偶数的时候他就会发生变化,如下图:
在这里插入图片描述
第三列的2往上跳2步的时候到达了6这个位置,但6已经被占据了,只能退而求其次连上5这个数,那么这也就导致了这个差值为1的出现。接下来后面的所有数都会比正常的少1。

于是规律推完,此题结束!

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mac=1e5+10;

vector<int>g[mac];
int vis[mac];

int main(int argc, char const *argv[])
{
	int n,k,len;
	scanf ("%d%d",&n,&k);
	if (k==1){
		for (int i=1; i<=n; i++)
			printf("%d%c",i,i==n?'\n':' ');
		return 0;
	}
	len=n/k;
	if (len%2==0){
		int nb=1;
		for (int i=1; i<=len/2; i++){
			for (int j=1; j<=k; j++){
				g[j].push_back(nb);
				g[j].push_back(n-nb+1);
				nb++;
			}
		}
		for (int i=1; i<=k; i++){
			for (auto x:g[i])
				printf("%d ",x);
			printf("\n");
		}
	}
	else {
		int ns=k;
		vis[ns]=1;
		for (int i=1; i<=k; i++){
			g[i].push_back(i);
			if (len>1){
				int su=(i+k/2)%(k+1);
				if (i+k/2>k) su++;
				g[i].push_back(su);
				g[i].push_back(ns);
				ns-=2;
				if (ns<=0) ns+=k;
				if (!vis[ns]) vis[ns]=1;
				else vis[--ns]=1;
			}
		}
		if (len>3){
			for (int i=1; i<=k; i++){
				for (int j=4; j<=(len-3)/2+3; j++){
					g[i].push_back(i);
					g[i].push_back(k-i+1);
				}
			}
		}
		for (int i=1; i<=k; i++){
			int sum=0;
			for (int j=0; j<len; j++){
				printf("%d ",g[i][j]+sum);
				sum+=k;
			}
			printf("\n");
		}
	}
	return 0;
}
posted @ 2020-11-07 18:44  lonely_wind  阅读(331)  评论(0编辑  收藏  举报