【JZOJ6233】【NOI2019模拟2019.6.27】心的旋律(思维题)

Description

  • 对于一个两边各有 n n n个点的二分图的左边一个点集 A A A,定义 F ( A ) F(A) F(A)为右边至少和 A A A中的一个点相邻的点的集合。
  • 给定一个 K K K,要求构造一个二分图,使得对于所有点集 A A A ∣ F ( A ) ∣ &lt; ∣ A ∣ |F(A)|&lt;|A| F(A)<A有恰好 K K K次成立。

Data Constraint

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

Solution

  • 对于左边的点,假定第 i i i个连向的点完全包含第 i − 1 i-1 i1个连向的点,且 d i − d i − 1 ≤ 1 d_i-d_{i-1}≤1 didi11 d i d_i di表示左边点 i i i的度数),则我们有一个结论:
  • 对于一种方案,将其 d 1 ∼ d n d_1\sim d_n d1dn压缩成一个二进制数 ( d n d n − 1 d n − 2 … … d 1 ) 2 (d_nd_{n-1}d_{n-2}……d_1)_2 (dndn1dn2d1)2;然后将这些数按1的个数为第一关键字从少到多、按大小为第二关键字从大到小排序,则最后某个数的序号即为该方案的 ∣ F ( A ) ∣ ≥ ∣ A ∣ |F(A)|≥|A| F(A)A成立次数(记为 c n t cnt cnt)。

  • 考虑证明上述结论。
  • 对于一种方案,记 B x B_x Bx为某个满足 d i − 1 = d i − 1 d_i-1=d_{i-1} di1=di1 i i i(包括1),则有 B ( 1 , 2 , … … , m ) B(_{1,2,……,m}) B(1,2,,m) m m m为不同的度数个数)。若不考虑空集,则:
    c n t = ∑ i = 1 n ∑ j = 1 d i ( i − 1 j − 1 ) = ∑ i = 1 m ( n i ) − ( B i − 1 i ) 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} cnt=i=1nj=1di(i1j1)=i=1m(ni)(Bi1i)
  • 那么比如有一种方案 ( 0100 ) 2 (0100)_2 (0100)2,我们将其中的1右移一位变成 ( 0010 ) 2 (0010)_2 (0010)2,其实相当于令 d 2 d_2 d2++,则根据左式 c n t cnt cnt++。也就是说,对于一种方案的二进制数,若其中的1不全在最右,则我们必能右移某一个1使其 c n t cnt cnt++。
  • 而如果某一状态的二进制数中的1全在最右,比如 ( 00000111 ) 2 (00000111)_2 (00000111)2,则其 c n t cnt cnt++就会变成 ( 11110000 ) 2 (11110000)_2 (11110000)2。因为根据右式, ( 00000111 ) 2 (00000111)_2 (00000111)2 c n t = ( 8 1 ) + ( 8 2 ) + ( 8 3 ) cnt=\begin{pmatrix} 8 \\ 1 \\ \end{pmatrix}+\begin{pmatrix} 8 \\ 2 \\ \end{pmatrix}+\begin{pmatrix} 8 \\ 3 \\ \end{pmatrix} cnt=(81)+(82)+(83) ( 11110000 ) 2 (11110000)_2 (11110000)2的cnt与其的差值为 c n t = ( 8 4 ) − ( 7 4 ) − ( 6 3 ) − ( 5 2 ) − ( 4 1 ) = ( 4 0 ) = 1 cnt=\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 cnt=(84)(74)(63)(52)(41)=(40)=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("");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值