【JZOJ6233】【NOI2019模擬2019.6.27】心的旋律(思維題)

Description

  • 對於一個兩邊各有nn個點的二分圖的左邊一個點集AA,定義F(A)F(A)爲右邊至少和AA中的一個點相鄰的點的集合。
  • 給定一個KK,要求構造一個二分圖,使得對於所有點集AAF(A)<A|F(A)|<|A|有恰好KK次成立。

Data Constraint

  • n32,K[0,2n]n≤32,K\in[0,2^n]

Solution

  • 對於左邊的點,假定第ii個連向的點完全包含第i1i-1個連向的點,且didi11d_i-d_{i-1}≤1did_i表示左邊點ii的度數),則我們有一個結論:
  • 對於一種方案,將其d1dnd_1\sim d_n壓縮成一個二進制數(dndn1dn2d1)2(d_nd_{n-1}d_{n-2}……d_1)_2;然後將這些數按1的個數爲第一關鍵字從少到多、按大小爲第二關鍵字從大到小排序,則最後某個數的序號即爲該方案的F(A)A|F(A)|≥|A|成立次數(記爲idid)。

  • 考慮證明上述結論。
  • 對於一種方案,記BxB_x爲某個滿足di1=di1d_i-1=d_{i-1}ii(包括1),則有B(1,2,,m)B(_{1,2,……,m})mm爲不同的度數個數)。若不考慮空集,則:
    cnt=i=1nj=1di(i1j1)=i=1m(ni)(Bi1i)cnt=\sum_{i=1}^n\sum_{j=1}^{d_i}\begin{pmatrix} i-1 \\ j-1 \\ \end{pmatrix}=\sum_{i=1}^m\begin{pmatrix} n \\ i \\ \end{pmatrix}-\begin{pmatrix} B_i-1 \\ i \\ \end{pmatrix}
  • 那麼比如有一種方案(0100)2(0100)_2,我們將其中的1右移一位變成(0010)2(0010)_2,其實相當於令d2d_2++,則根據左式idid++。也就是說,對於一種方案的二進制數,若其中的1不全在最右,則我們必能右移某一個1使其idid++。
  • 而如果某一狀態的二進制數中的1全在最右,比如(00000111)2(00000111)_2,則其idid++就會變成(11110000)2(11110000)_2。因爲根據右式,(00000111)2(00000111)_2cnt=(81)+(82)+(83)cnt=\begin{pmatrix} 8 \\ 1 \\ \end{pmatrix}+\begin{pmatrix} 8 \\ 2 \\ \end{pmatrix}+\begin{pmatrix} 8 \\ 3 \\ \end{pmatrix}(11110000)2(11110000)_2的cnt與其的差值爲cnt=(84)(74)(63)(52)(41)=(40)=1cnt=\begin{pmatrix} 8 \\ 4 \\ \end{pmatrix}-\begin{pmatrix} 7 \\ 4 \\ \end{pmatrix}-\begin{pmatrix} 6 \\ 3 \\ \end{pmatrix}-\begin{pmatrix} 5 \\ 2 \\ \end{pmatrix}-\begin{pmatrix} 4 \\ 1 \\ \end{pmatrix}=\begin{pmatrix} 4 \\ 0 \\ \end{pmatrix}=1。其他以此類推。

  • 於是,我們可以先預處理出組合數,減一減算出要求的方案的二進制數中1的數量,以及它在那些二進制數的第幾位;繼而算出該方案的每一位。

Code

#include <bits/stdc++.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;

ll i,j,n,k,C[33][33],x,a[33];

int main()
{
	freopen("circle.in","r",stdin);
	freopen("circle.out","w",stdout); 
	scanf("%lld%lld",&n,&k); 
	if(!(k=(1<<n)-k)) return puts("-1"),0;
	fo(i,0,n)
	{
		C[i][0]=1;
		fo(j,1,i) C[i][j]=C[i-1][j]+C[i-1][j-1];
	}
	fo(i,0,n) fo(j,i+1,n) C[i][j]=1;
	for(x=0;k>C[n][x];k-=C[n][x++]);
	fo(i,1,n)
	{
		if(k>C[n-i][x-1]) {k-=C[n-i][x-1]; continue;}
		x--; a[n-i]=1;
	}
	x=0;
	fo(i,0,n-1)
	{
		x+=a[i];
		fo(j,1,x) printf("1 ");
		fo(j,j,n) printf("0 ");
		puts("");
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章