zoukankan      html  css  js  c++  java
  • poj3252

    第一道组合数学题,连跪一天。。

    没有discuss根本做不出来,但是想想不是很难。

    首先,

    RoundNumber[start, end] = RoundNumber[0,start] - RoundNumber[0,end - 1] = RoundNumber[0, start + 1] - RoundNumber[0, end]

    这是容易证明的。因为一个数字是否是所谓“RoundNumber”,只跟它自己有关,也就是说转化成二进制的0的个数是否大于1的个数有关。那么他们(独立的数字,如1,2,3,4)之间是相互独立的。至于为何要加一或者减一,因为是要包含区间边界,无论是否小于等于它都会包含(省事儿),所以最后处理一下。

    《组合数学》第二章“排列与组合”中,阐述了几个原理:加法原理、减法原理、乘法原理。各自的前提是不同的,需要仔细去了解。

    重点不在上面,上面只是基础。

    首先在高中我们学过组合数的定义:


    然后它具有以下常用性质:

    1.

    2.

    3.

    4.

    性质3常用于打表,因为其具递推的性质。


    切入正题,假设有如下二进制数:


    问其是否是RoundNumber?答案是肯定的。

    最一开始我们知道,要想求RN[start,end],我们只需要求RN[0,start+1]-RN[0,end]。归根结底是求RN[0,x]。

    把这个八位二进制数分情况讨论一下,比它小的分两种情况,一是1至7位数,二是八位数。

    情况一:

    一个二进制,长度为Len的数,若使0的个数大于1的个数,可以这么安排:

    若Len是奇数,即Len=2*k+1,最高位是1,其余2k位,则有:


    至此,Len是奇数时我们解决了。可以直接算这些组合数(从表中直接取,以下代码就是这么操作的),也可以利用一下上面提供的性质。由性质2知,在性质1和式函数中,最头的两个是对称相等的。那么,上式恰好等于:


    若Len是偶数,Len=2*k,最高位是1,其余2k-1位,同理可得:


    情况二:当位数为8时:

    先放大一下这个二进制数:


    可以清晰地看到,第四位,我标记了1。如果将1改为0,那么剩下的四位任意填数都满足该数(新的)小于这个二进制数(10011000)B。但是不能任意填,还是要满足0的个数大于1的个数,那么我们有如下结论:

    令l为长度,i为当前改变的“1”的位置,如图中的位置4,zero为0的计数(绝对计数、不包含被改变的第四位数1),a为需要填数的位置(下图中的虚线框)中1的个数,b为需要填数的位置中0的个数。


    有如下等式:


    有如下不等式:


    解得:


    这个式子说明了,至少要填那么b个零,也就是l/2-(zero+1)。注意奇偶。至多呢?至多全填满呗。填多少?i-1个(空格数)呗。注意,程序中是从高位到地位搜索,i的位置表示的是绿色的1的位置,i-1是空格(虚线框)的个数。

    至此,问题解决了,那么代码就很简单了。

    #include<iostream>
    
    using namespace std;
    
    int c[33][33] = { 0 };
    int bin[35];  //十进制n的二进制数
    
    void combinations()
    {
    	for (int i = 0; i <= 32; i++)
    	{
    		for (int j = 0; j <= i; j++)
    		{
    			if (!j || i == j)
    			{
    				c[i][j] = 1;
    			}
    			else
    			{
    				c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
    			}
    		}
    	}
    	return;
    }
    
    void dec_to_bin(int n)
    {
    	bin[0] = 0;
    	while (n)
    	{
    		bin[++bin[0]] = n % 2;
    		n /= 2;
    	}
    	return;
    }
    
    int round(int n)
    {
    	int i, j;
    	int sum = 0;
    	dec_to_bin(n);
    
    	/*计算长度小于bin[0]的所有二进制数中RN的个数*/
    
    	for (i = 1; i < bin[0] - 1; i++)
    	{
    		for (j = i / 2 + 1; j <= i; j++)
    		{
    			sum += c[i][j];
    		}
    	}
    			
    	/*计算长度等于bin[0]的所有二进制数中RN的个数*/
    
    	int zero = 0;  //从高位向低位搜索过程中出现0的位的个数
    	for (i = bin[0] - 1; i >= 1; i--)
    	{
    		if (bin[i])
    		{
    			for (j = (bin[0] + 1) / 2 - (zero + 1); j <= i - 1; j++)
    			{
    				sum += c[i - 1][j];
    			}
    		}
    		else zero++;
    	}
    	return sum;
    }
    
    int main()
    {
    	combinations();
    	int a, b;
    	while (cin >> a >> b)
    	{
    		cout << round(b + 1) - round(a) << endl;
    	}
    }
    


    组合数学,一跪一天,爽!

  • 相关阅读:
    3.6 批量维护来源准则/查看来源准则
    3.5 供货比例(来源准则)控制
    3.4 新供应商引入
    3.3 集团化采购管理
    3.2 采购管理目标
    3.1 采购管理规划
    2.8 生产辅料管理
    2.7 车间任务的批量移动和批量完工入库
    2.6 自动更新车间任务的供应类型和完工子库
    2.5 总装与部装跟单任务的同步发放
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3243989.html
Copyright © 2011-2022 走看看