【题解】数球

题目描述

小 A 有 \(n\) 个球,编号分别为 \(1\) 到 \(n\),小 A 每次都会从 \(n\) 个球中取出若干个球,至少取一个,至多取 \(n\) 个,每次取完再放回去,取出的球需要满足以下两个条件:

  1. 每次取出的球的个数两两不同。
  2. 每次取出的球的集合两两不包含。

包含是指,对于两次取球,取的数目少的那次取球的所有球都出现在取的数目多的那次取球中。

例如 \(\{1,2\}\) 和 \(\{1,2,4\}\),\(\{1,2\}\) 和 \(\{2,3\}\) 则不算作包含。

而小 A 现在突然想知道他最多能进行多少次这样的操作,并希望你能给出具体的取球方案。

输入格式

一个整数 \(n\)。

输出格式

第一行一个数 \(k\),表示能进行的最多次数。

接下来 \(k\) 行,每行第一个整数 \(p\),表示这次取的球数;

接下来 \(p\) 个数表示这次取的球的编号,编号只需要不同,不需要按照顺序输出,

计分标准

本题设有 Special Judge。

对于每个测试点,每组数据第一行正确可以获得 \(20\%\) 的分,如果第一行和方案均正确获得 \(100\%\) 的分。

数据范围

评测时间限制 \(1000\ \mathrm{ms}\),空间限制 \(512\ \mathrm{MiB}\)。

  • 对于 \(30\%\) 的数据,\(n\le 7\);
  • 对于 \(50\%\) 的数据,\(n\le 20\);
  • 对于 \(70\%\) 的数据,\(n\le 100\);
  • 对于 \(100\%\) 的数据,\(4\le n\le 1000\)。

分析

这道题是一道典型的组合类结论题,需要计算上限和构造。

由于部分分没有什么可讲的,所以我们直接去考虑满分算法。

\(100\ \mathtt{pts}\)

遇到这种组合题,首先考虑答案上界。

一个显而易见的结论是,不可能有超过 \(n\) 个集合。(否则根据抽屉原理,必有两个集合大小相同)

一个更显而易见的结论是,不可能存在大小为 \(n\) 的集合。(废话,否则剩下的所有集合都是这个集合的子集)

一个不是那么显然的结论是,大小为 \(1\) 的集合与大小为 \(n-1\) 的集合不共存。为什么?

根据题意,显然如果能够共存,一定长这个样子:

那么问题来了:大小为 \(2\)(或者更大的)的怎么办?

首先,不可能在 \(1\) 这一边,这样就会包含 \(1\)。

但是,又不能不在 \(1\) 这一边,不然就会被 \(n-1\) 包含。矛盾。

(左右为♂难)

所以,理论最大答案就是 \(n-2\)。



接下来我们考虑构造,这才是这道题真正的难点。

首先,我们不妨先来试一下。

(注:接下来的构造过程基于 \(1\) 到 \(n-2\) 的集合构造,如果使用 \(2\) 到 \(n-1\) 也会得到类似的结论。构造方式不止这一种,还有很多种方式可以做到)

比如对于一个大小为 \(n\) 的球集合,我们要先留出一个位子给 \(1\) 用,再放上 \(n-2\) 和 \(2\),就像这样:

(易证这是唯一可能的情况,不包括顺序的打乱)

接下来我们试图放上 \(3\),发现条件与 \(2\) 类似,不要放在 \(1\) 上,也不要全部在 \(n-2\) 上。

接下来所有的集合都有类似的规则。

那么,我们是不是可以对这个大集合做一些操作,使得这些规则消除呢?

我们发现,除了 \(1\) 和 \(n-2\) 以外,其余所有的集合都必须有第二个元素。

同时,\(1\) 也是一个不必要的存在,可以将其视为空无,或者屏蔽。

所以,我们对大集合做出这样的操作——把 \(1\),\(2\) 两个元素删掉,同时干掉 \(1\) 和 \(n-2\) 这两个集合。

我们惊奇地发现,这样的新集合就是 \(n-2\) 时的问题。

不懂?看图就知道了:

于是,我们就可以递归求解了!

当然,我们也可以稍微动动脑筋,变成一个简单的循环问题。具体实现见代码。

Code

我们只要稍微转换一下就可以降低实现难度,更快地解决问题了。

我们可以记录一个数组 sta[i],来记录当前递归时接下来所有集合都要加进去的东西。

对于上一张图的每一层,先根据 sta[i] 输出这一层的两个集合,再往 sta[i] 里面加入这一层要求接下来所有集合必须包含的东西。

比如说,处理第一层时,那个剩下来的元素(图中第二个)就会被加入这个数组,接下来每一个集合都必须有这个元素。

当然,这道题的边界也是要稍微留留神的。尤其是奇偶性,如果是奇数的话就要再多输出一个集合。

为了加快速度,5ab 写了一个快写,因为这道题的输出量可能会到 \(10^6\)。

// @author 5ab

#include <cstdio>
using namespace std;

const int max_n = 1000;

// 不要那么在意变量名辣……
int dk[max_n>>1] = {};

void _write(int x)
{
	if (x > 9)
		_write(x / 10);

	putchar(x % 10 + ‘0‘);
}

inline void write(int x)
{
	if (x < 0)
	{
		putchar(‘-‘);
		x = -x;
	}

	_write(x);
}

int main()
{
	int n;

	scanf("%d", &n);
	write(n - 2);
	putchar(‘\n‘);

	for (int i = 0; i < n / 2 - 1; i++)
	{
		write(n - i - 2);
		putchar(‘ ‘);

		for (int j = 0; j < i; j++)
		{
			write(dk[j]);
			putchar(‘ ‘);
		}

		for (int j = 2 * i + 2; j < n; j++)
		{
			write(j + 1);
			putchar(‘ ‘);
		}

		putchar(‘\n‘);

		write(i + 1);
		putchar(‘ ‘);
		dk[i] = i * 2 + 2;

		for (int j = 0; j < i; j++)
		{
			write(dk[j]);
			putchar(‘ ‘);
		}
		write(dk[i] - 1);

		putchar(‘\n‘);
	}

	if (n & 1)
	{
		write(n / 2);
		putchar(‘ ‘);

		for (int i = 2; i <= n; i += 2)
		{
			write(i);
			putchar(‘ ‘);
		}

		putchar(‘\n‘);
	}

	return 0;
}

后记

这道题当时在考场上时只想到了上界,却不知道构造方法。

后来看了解题报告也是不知所云。

最后,经过一番摸索和试验,终于拼凑出一个做法,才有了这一篇题解。

有时,一些结论需要试验才能得出。试验一直是结论的试金石。要敢于试验,才能敢于下结论,最后证明。

原文地址:https://www.cnblogs.com/5ab-juruo/p/solution-20200329-ball.html

时间: 2024-10-14 03:44:33

【题解】数球的相关文章

HDU 6108 小C的倍数问题 数论

小C的倍数问题 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6108 Description 根据小学数学的知识,我们知道一个正整数x是3的倍数的条件是x每一位加起来的和是3的倍数.反之,如果一个数每一位加起来是3的倍数,则这个数肯定是3的倍数.现在给定进制P,求有多少个B满足P进制下,一个正整数是B的倍数的充分必要条件是每一位加起来的和是B的倍数. Input 第一行一个正整数T表示数据组数(1<=T<=20).接下来T行,每行一个正整数P(

PAT 甲级 A1075 (2019/02/18)

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 10010; struct PAT_Student{ int id; //考号 int score[6]; //每道题的分数 bool flag; //是否有能通过编译的提交 int all_score; //总分 int prefect_problem;//完美题解数 }stu[MAX

魔术球问题弱化版 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 我也不知道这个问题是哪里来的,所以没有题目链接...但是文末会给出几组数据. 题目描述 假设有 n 根柱子,现要按下述规则在这 n 根柱子中依次放入编号为 1,2,3,…的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何 2 个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在 n 根柱子上最多能放多少个球. 例如,在 4 根柱子上最多可放 11 个球. 对于给定的 n,计算在 n 根柱子上最多能

【BZOJ1026】windy数题解

题面 [题目描述] windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? [输入] 包含两个整数,A B. [输出] 一个整数. [输入样例一] 1 10 [输入样例二] 25 50 [输出样例一] 9 [输出样例二] 20 [数据规模和约定] 100%的数据,满足 1 <= A <= B <= 2000000000 . 题解 分析 头一次接触数位DP啊 然而这题只要这样

洛谷 P1106 删数问题 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1106 题目描述 键盘输入一个高精度的正整数N,去掉其中任意k个数字后剩下的数字按原左右次序将组成一个新的正整数.编程对给定的N和k,寻找一种方案使得剩下的数字组成的新数最小. 输出应包括所去掉的数字的位置和组成的新的正整数.(N不超过250位) 输入数据均不需判错. 输入输出格式 输入格式: n (高精度的正整数) k (需要删除的数字

CodeVS1039 数的划分 插图题解!

题目 题目描述 将整数n分成k份,且每份不能为空,任意两种划分方案不能相同(不考虑顺序). 例如:n=7,k=3,下面三种划分方案被认为是相同的. 1 1 5 1 5 1 5 1 1 问有多少种不同的分法. 输入描述 输入:n,k (6 输出描述 输出:一个整数,即不同的分法. 样例输入 7 3 样例输出 4 题解! 我们用dp[i][j]表示把数字i分成j份的方案数,那么: 1. i < j 时,不存在方案,dp[i][j]=0; 2. i >= j 时,考虑:     1) 当前方案存在“

Noip2006 2^k进制数题解

题目描述 Description 设r是个2k进制数,并满足以下条件: (1)r至少是个2位的2k进制数. (2)作为2k进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. (3)将r转换为2进制数q后,则q的总位数不超过w. 在这里,正整数k(1≤k≤9)和w(k<W≤30000)是事先给定的. 问:满足上述条件的不同的r共有多少个? 我们再从另一角度作些解释:设S是长度为w的01字符串(即字符串S由w个"0"或"1"组成),S对应于上述条件(3)

洛谷 P1005 矩阵取数游戏 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1005 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元

Noip2007矩阵取数游戏题解

题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n?m的矩阵,矩阵中的每个元素ai,j均 为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 每次取走的各个元素只能是该元素所在行的行首或行尾: 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分=被取走的元素值?2i, 其中i表示第i 次取数(从1 开始编号): 游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出