【题目】
题目描述:
小 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 3 4
备注:
【数据规模】
对于 30% 的数据,n ≤ 7。
对于 50% 的数据,n ≤ 20。
对于 70% 的数据,n ≤ 100。
对于 100% 的数据,4 ≤ n ≤ 1000。
【分析】
对于 30% 的数据直接达标找规律就行的(我就是这么做的)
然后找规律可以得到最多有 (n - 2)次选球(然后就又骗了 14 分)
一道构造题,之前没接触过,没什么思路,但其实讲了题解后就恍然大悟
现在对于 4,我们不直接转到 5,我们转到 6,怎么做呢(以下的 \ 代表换行)
那么 4(1 \ 3 4) 6(1 6 \ 3 4 6 \ 5 \ 1 2 3 4)就是一种可行的转法,很容易看出规律吧
具体就是在 4 中的每一行加一个 6,然后新添一行 5,然后新添一行 1 2 3 4
奇数变换规则和偶数相等,就不再赘述了
如果还是不懂可以多举几个例子或者看一下代码
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1005
using namespace std;
int num[N],a[N][N];
void init(int n)
{
if(n%2)
{
a[1][1]=1;num[1]=1;
a[2][1]=2;a[2][2]=3;num[2]=2;
a[3][1]=3;a[3][2]=4;a[3][3]=5;num[3]=3;
}
else
{
a[1][1]=1;num[1]=1;
a[2][1]=3;a[2][2]=4;num[2]=2;
}
}
void work(int x)
{
int i;
for(i=1;i<=x-4;++i)
a[i][++num[i]]=x;
a[x-3][1]=x-1;
for(i=1;i<=x-2;++i)
a[x-2][i]=i;
num[x-3]=1;
num[x-2]=x-2;
}
void write(int n)
{
int i,j;
printf("%d\n",n-2);
for(i=1;i<=n-2;++i)
{
printf("%d ",num[i]);
for(j=1;j<=num[i];++j)
printf("%d ",a[i][j]);
printf("\n");
}
}
int main()
{
// freopen("ball.in","r",stdin);
// freopen("ball.out","w",stdout);
int n,i,begin;
scanf("%d",&n);
init(n);
begin=n%2?7:6;
for(i=begin;i<=n;i+=2)
work(i);
write(n);
// fclose(stdin);
// fclose(stdout);
return 0;
}