• POJ3252


    题目链接:https://vjudge.net/problem/POJ-3252

    知识点:组合数的一个递推式:C(i,j)=C(i-1,j-1)+C(i-1,j) (易证)

    解题思路: 

      要求有多少个round number小于或等于某一个数S (其二进制位数为t),我们分三类进行:

      1、看看S本身是不是round number。对于该类,只需将S转换成二进制并记录其0、1个数即可验证;

      2、找出二进制位数小于 t 的所有round number。我们给出一个int cul (int n)函数来求二进制长度为n的所有round num,首先需要知道的是:其第一位必定为1。我们要保证0的个数多于或等于1的个数,则我们可以得出如下公式:若n为奇数,则cul(n) = C(n-1,n/2+1) + C(n-1,n/2+2) + ... + C(n-1,n-1); 若n为偶数,则cul(n) = C(n-1,n/2) + C(n-1,n/2+1) + ... + C(n-1,n-1), 另外,由于当n=1,我们会求到 C(0,1),这显然不妥,于是我们在函数中加上条件:if(n<=1)    return 0;  。则该类round number的总数为: cul(t-1) + cul(t-2) + ... + cul(1)。

      3、现在需要找出二进制位数等于 t 的 round number。我们用 cnt1 和 cnt0 两个变量记录S中0和1个数的实时变化。首先,每个数的第一个数都是1,则初始化cnt1=1,cnt0=0.接下来我们遍历给出的数的后面的每一位,如果该位上的数为0,则只需cnt0++即可,因为我们能且只能在该位上放置0;如果该位上的数是1,则我们可以先将该位数看为0,"暂时" (注意,只是暂时的,等下还要把cnt0恢复回去)地把cnt0看为 cnt0+1 ,那么后面的数字肯定是无论我们怎么取值,都肯定小于S,这就有点像第2类,求二进制位数小于某个数的所有round number, 但是在这里还需要考虑 cnt1 和 cnt0 需要保证0的总个数大于或等于1的总个数,我们设0的个数为 j ,后面的二进制位数为 i ,则在此处的round number数为:C(i-1,i-1) + C(i-1,i-2) + ... + C(i-1,j) . 需要保证 j + cnt0 >= i - j + cnt1,这里的cnt0其实就是cnt0 + 1,详情请参考代码。最后别忘了cnt1++。

    AC代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 using namespace std;
     4 int C[35][35];
     5 void init(){
     6     C[0][0]=1;
     7     C[1][1]=C[1][0]=1;
     8     for(int n=2;n<35;n++){
     9         C[n][0]=C[n][n]=1;
    10         for(int m=1;m<n;m++)
    11             C[n][m]=C[n-1][m-1]+C[n-1][m];
    12     }
    13 }
    14 int cul(int n){
    15     if(n<=1)    return 0;
    16     int s,ans=0;
    17     if(n%2) s=n/2+1;
    18     else    s=n/2;
    19     for(int i=s;i<n;i++)
    20         ans+=C[n-1][i];
    21     return ans;
    22 }
    23 int finds(int num){
    24     if(num<=1)  return 0;
    25     int tmp=num,dig[50];
    26     int len,lastone;
    27     int c1=1,c0=0;
    28     for(len=0;tmp>0;tmp=tmp>>1,len++){
    29         if(len>0){
    30             if((tmp<<1)<lastone){
    31                 dig[len]=1;
    32                 c1++;
    33             }
    34             else{
    35                 dig[len]=0;
    36                 c0++;
    37             }
    38         }
    39         lastone=tmp;
    40     }
    41     dig[len]=1;
    42     int ans=0;
    43     if(c1<=c0)  ans++;
    44 
    45     for(int i=1;i<=len-1;i++)
    46         ans+=cul(i);
    47 
    48     int cnt0=0,cnt1=1;
    49     for(int i=len-1;i>0;i--){
    50         if(dig[i]==0)   cnt0++;
    51         else{
    52             for(int j=i-1;j>=0;j--){
    53                 if(2*j<i+cnt1-2-cnt0) break;
    54                 ans+=C[i-1][j];
    55             }
    56             cnt1++;
    57         }
    58     }
    59     return ans;
    60 }
    61 int main()
    62 {
    63     init();
    64     int s,f;
    65     scanf("%d%d",&s,&f);
    66     printf("%d
    ",finds(f)-finds(s-1));
    67     return 0;
    68 }
    View Code
    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    请多指教
    第九周作业总结
    win10系统开机输入密码黑屏解决方法
    第八周作业总结
    第七周作业总结
    第六周作业总结
    第五周作业总结
    第四周作业
    第三周作业
    2019年春季学期第二周作业
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/7227279.html
Copyright © 2020-2023  润新知