1. 程式人生 > >atcoder tenka1 2018 D - 結論 - 構造

atcoder tenka1 2018 D - 結論 - 構造

題目大意:給定n和n個元素1到n,要求構造若干集合,使得每個元素出現在恰好兩個集合中,並且任意兩個集合交集大小恰好是1.
題解:假定有k個集合,那麼就會有k(k-1)/2個交集。顯然這k(k-1)/2個交集兩兩不同,並且由於任意一個元素都出現了恰好兩次,因此至少兩個集合的交集似乎它。因此k(k-1)/2=n。反過來的構造也是很顯然的,對每個元素欽定兩兩不同的一對無序集合即可。

#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long #define db long double #define pb push_back #define mp make_pair #define fir first #define sec second #define debug(x) cerr<<#x<<"="<<x #define sp <<" " #define ln <<endl using namespace std; typedef pair<int,int> pii; typedef set<int>
::iterator sit; inline int inn() { int x,ch;while((ch=gc)<'0'||ch>'9'); x=ch^'0';while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; } const int N=100010;vector<int> v[N]; int main() { int n=inn(),k=0,cnt=0; if(n==1) return !printf("Yes\n2\n1 1\n1 1\n");
rep(i,1,n) if((lint)i*(i-1)/2==n) { k=i;break; } if(!k) return !printf("No\n"); rep(i,1,k) rep(j,i+1,k) cnt++,v[i].pb(cnt),v[j].pb(cnt); printf("Yes\n%d\n",k); rep(i,1,k) { printf("%d ",(int)v[i].size()); Rep(j,v[i]) printf("%d ",v[i][j]); printf("\n"); } return 0; }