NOIP模拟 数球(思维题)

【题目描述】

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

(1)每次取出的球的个数两两不同。

(2)每次取出的球的集合两两不包含。

包含是指,对于两次取球,对于取的数目少的那次取球的所有球都出现在取的数目多的那次取球中,例如{1,2}和{1,2,4},{1,2}和{2,3}则不算作包含。

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

【输入样例】

一个整数n。

【输出样例】

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

接下来k行,每行第一个整数p,表示这次取的球数,接下来p个数表示这次取的球的编号,编号只需要不同,不需要按照顺序输出,本题设有spj。

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

【样例输入】

4

【样例输出】

2

1 1

2 2 3

【备注】

对于30%的数据,n<=7。

对于50%的数据,n<=20。

对于70%的数据,n<=100。

对于100%的数据,4<=n<=1000。

 

【题目分析】

首先对于30%甚至50%的数据,打表是完全没问题的,那么对于可打表的数据,我们可以发现一个规律:最多可以取的次数为n-2,并且恒成立,下面给出证明:

(1):n为奇数

n最小为5,此时最大次数为3,可为{1},{2,3},{2,4,5},对于7,我们可以在每一组后添1个7,因为原组合不互相包含,那么加上一个7后仍不互相包含,然后将6作为单独一组,以此类推,所有为奇数的n均可以用这种方式构造出。

(2):n为偶数

同(1),n最小为4,最大次数为2,{1},{2,3},对于6可以在每一组后添1个6,因为原组合不互相包含,那么加上一个6后仍不互相包含,然后将5作为单独一组,以此类推,所有为偶数的n均可以用这种方式构造出。证毕。

然后这道题就比较简单了,代码见下:

【代码~】

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1010;

int n,num;
int f[MAXN<<1][MAXN];

int main()
{
	scanf("%d",&n);
	printf("%d\n",n-2);
	f[num=MAXN][0]=f[MAXN][1]=1;
	if(n&1)
	{
		for(int i=5;i<=n;i+=2)
		{
			num--;
			f[num][f[num][0]=1]=i-1;
			for(int j=num+1;j<=num+i-4;++j)
			  f[j][++f[j][0]]=i;
			for(int j=1;j<=i-2;++j)
			  f[num+i-3][j]=j;
			f[num+i-3][0]=i-2;
		}
	}
	else
	{
		f[num+1][0]=2;
        f[num+1][1]=2,f[num+1][2]=3;
        for(int i=6;i<=n;i+=2)
        {
            num--;
            f[num][f[num][0]=1]=i-1;
            for(int j=num+1;j<=num+i-4;j++) f[j][++f[j][0]]=i;
            for(int j=1;j<=i-2;j++) f[num+i-3][j]=j;
            f[num+i-3][0]=i-2;
        }
	}
	for(int i=num;i<num+n-2;++i)
	{
		printf("%d",f[i][0]);
		for(int j=1;j<=f[i][0];++j)
		  putchar(' '),printf("%d",f[i][j]);
		cout<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/g21glf/article/details/82850231