atcoder tenka1 2018 D - 結論 - 構造
阿新 • • 發佈:2018-11-01
題目大意:給定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;
}