数球[构造]

Description

小A有n个球,编号分别为1到n,小A每次都会从n个球中取出若干个球,至少取一个,至多取n个,每次取完再放回去,需要满足以下两个条件。 每次取出的球的个数两两不同。 每次取出的球的集合两两不包含。包含是指,对于两次取球,对于取的数目少的那次取球的所有球都出现在取的数目多的那次取球中,例如{1,2}和{1,2,4},{1,2}和{2,3}则不算作包含。 而小A现在突然想知道他最多能进行多少次这样的操作,并希望你能给出具体的取球方案。

Input 一个整数n。

Output 第一行一个数k,表示能进行的最多次数。 接下来k行,每行第一个整数p,表示这次取的球数,接下来p个数表示这次取的球的编号,编号只需要不同,不需要按照顺序输出.

Sample Input

4

Sample Output

2

1 1

2 3 4

对于30%的数据,n<=7。 对于50%的数据,n<=20。 对于70%的数据,n<=100。 对于100%的数据,4<=n<=1000。


分析

第一次接触这种题,

暴力搜索只有50分...

但对于n的输出,竟然可以用n-2推出----

首先,我们需要发现一共可以有n-2种,类似这样

1 2 3 4 5 6

2 3 

3 4 5

2 4 5 6

其次,我们需要找到一种方法从n-2的答案推到n的答案

假设现在是

1 a1

2 a2 a3

3 a3 a4 a5

我们要将a6,a7填进去

考虑将当前行每行增加一个,然后前面添一个,后面添一个

发现当当前的123排后面全部加上一个a7,只有我们后面填的不出现a7一定就不会包涵

进而,第一个只能是a6不然一定会被包涵

最后一排不出现a6,a7 a1-5 正好可以

于是变成

1 a6

2 a1 a7

3 a2 a3 a7

4 a3 a4 a5 a7

5 a1 a2 a3 a4 a5


所以说,我们要寻找上一层答案与这一层的关系

不是去搜索有哪些方法,而是一步一步推出有哪些方法


#include<bits/stdc++.h>
#define N 1005
using namespace std;
int n,a[N][N];
int main(){
	cin>>n;cout<<n-2<<endl;
	a[1][1]=1,a[2][1]=2,a[2][2]=3;
	for(int i=(n&1)?5:6;i<=n;i+=2){
		for(int j=1;j<=i-4;j++){//最每行后一个填n 
			a[j][j+1]=i;
		}
		for(int j=i-4;j>=1;j--){// 全部下移一行 
			for(int k=1;k<=j+1;k++) a[j+1][k]=a[j][k];
			a[j][j+1]=0;
		}
		a[1][1]=i-1; //第一个填n-1 
		for(int k=1;k<=i-2;k++) a[i-2][k]=k;//最后一排填1-n-2 
	}
	for(int i=1;i<=n-2;i++){
		cout<<i<<" ";
		for(int j=1;j<=i;j++)cout<<a[i][j]<<" ";
		cout<<endl;
	}return 0;
}

当然,这样是O(n^3)的

因为答案不要求按顺序,所以我们可以直接把第一个放到i-1行而不是第一行

这样就是O(n^2)了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值