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
1
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)了