1. 程式人生 > >【2018/09/22】T3

【2018/09/22】T3

數球(44/100)

描述

小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%,50%:手算,搜尋。  70%&100%:首先我們可以知道答案是 n-2,因為總共有 n種大小的子集,大小為 n的肯定不能選,因為必然包含大小為 1的子集。大小為n-1的也不能選,因為選的話,那麼大小為 1的必然不能在大小為n-1的子集裡,大小為 2的不能全在大小為 n-1的子集裡,這樣大小為1的必然被大小為 2的包含,答案至多為 n-2。 

設n時答案為A(1),A(2),……,A(n-2)。

1、隔兩個構造。 B(i)=A(i)∪{n+2}(1<=i<=n-2),B(n-1)={n+1},B(n)={1,2,…,n}  2、隔一個構造。 n+1時,B(i)={1,2,…,n}\A(i),B(n-1)={n+1}。 

【程式碼】

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int k,f[1009][1009],n,num[1009];
int main(){
	scanf("%d",&n);
	if(n%2==0){
		printf("%d\n",n-2);
		int ceng=2,now=4,nn=n;
		f[1][1]=1;f[2][1]=3;f[2][2]=4;
		num[1]=1;num[2]=2;
		n=(n-4)/2;
		while(n--){
			now=now+2;
			for(int i=1;i<=ceng;++i){
				f[i][++num[i]]=now;
			}
			f[++ceng][++num[ceng]]=now-1;
			++ceng;num[ceng]=now-2;
			for(int i=1;i<=now-2;++i)
				f[ceng][i]=i;
		}
		for(int i=1;i<=nn-2;++i){
			printf("%d",num[i]);
			for(int j=1;j<=num[i];++j)
				printf(" %d",f[i][j]);
			printf("\n");
		}
	}
	else{
		printf("%d\n",n-2);
		int ceng=3,now=5,nn=n;
		f[1][1]=1;f[2][1]=2;f[2][2]=3;f[3][1]=2;f[3][2]=4;f[3][3]=5;
		num[1]=1;num[2]=2;num[3]=3;
		n=(n-5)/2;
		while(n--){
			now=now+2;
			for(int i=1;i<=ceng;++i)	f[i][++num[i]]=now;
			f[++ceng][++num[ceng]]=now-1;
			++ceng;num[ceng]=now-2;
			for(int i=1;i<=now-2;++i)
				f[ceng][i]=i;
		}
		for(int i=1;i<=nn-2;++i){
			printf("%d",num[i]);
			for(int j=1;j<=num[i];++j)
				printf(" %d",f[i][j]);
			printf("\n");
		}
	}
	return 0;
}