zoukankan      html  css  js  c++  java
  • noip2006 2^k进制数

    描述

    设r是个2k 进制数,并满足以下条件:
    (1)r至少是个2位的2k 进制数。

    (2)作为2k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位。

    (3)将r转换为2进制数q后,则q的总位数不超过w。

    在这里,正整数k(1≤k≤9)和w(k<W≤30000)是事先给定的。

    问:满足上述条件的不同的r共有多少个?
    我们再从另一角度作些解释:设S是长度为w 的01字符串(即字符串S由w个“0”或“1”m组成),S对应于上述条件(3)中的q。将S从右起划分为若干个长度为k 的段,每段对应一位2k进制的数,如果S至少可分成2段,则S所对应的二进制数又可以转换为上述的2k 进制数r。

    例:设k=3,w=7。则r是个八进制数(23=8)。由于w=7,长度为7的01字符串按3位一段分,可分为3段(即1,3,3,左边第一段只有一个二进制位),则满足条件的八进制数有:
    2位数:高位为1:6个(即12,13,14,15,16,17),高位为2:5个,…,高位为6:1个(即67)。共6+5+…+1=21个。

    3位数:高位只能是1,第2位为2:5个(即123,124,125,126,127),第2位为3:4个,…,第2位为6:1个(即167)。共5+4+…+1=15个。

    所以,满足要求的r共有36个。

    格式

    输入格式

    输入文件只有1行,为两个正整数,用一个空格隔开:
    k W

    输出格式

    输出文件为1行,是一个正整数,为所求的计算结果,即满足条件的不同的r的个数(用十进制数表示),要求最高位不得为0,各数字之间不得插入数字以外的其他字符(例如空格、换行符、逗号等)。

    (提示:作为结果的正整数可能很大,但不会超过200位)

    -----------------------------------------------------------------------
    正解=组合数学
    注意这句话:作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位。
    其实这是在暗示组合数,
          显然r中的不会有相同的位
          如果每一位都不同,显然只有严格递增的排列是合法的
    这便是组合- =,
    将 r 转化成这种形式(设k为3) 000 000 000 000 
          显然除首位外每一位的取值范围为 000 to 111(2^k-1)
          在首位为0的情况下,最多可取 w/k 位,且题目要求大于2位,
          则在首位为0的合法解有 C(2^k-1,i)(2<=i<=w/k) ,
    Ps. 如果 w 模 k 等于 0 仅考虑上述情况即可。
    考虑首位不为0的情况
          显然首位不为0的话,r 就有 w/k+1 位,
          除首位外还有w/k位,
          可以枚举首位的取值范围为 1 to 2^(w mod k)-1
          设首位取值为 val  
          则剩下 w/k 位 取值范围为 val+1 to 2^k-1 
          也就是有 2^k-1-val 个数可取
          所以首位不为0的合法解有  C(2^k-1-val,w/k)(1<=val<=2^(w mod k)-1) 
    所以上述两者相加便是正解(需要高精运算)
    Ps. 实际编程时存在一些计算边界。
    代码如下:
     1 #include<cstring>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #include<string>
     5 #include<iostream>
     6 #include<queue>
     7 #define INF 99999999
     8 #define LL long long
     9 using namespace std;
    10 struct STR{
    11     int s[200];
    12 }c[501][501]; 
    13 STR One,ans;
    14 void put(STR a){
    15     printf("%d",a.s[a.s[0]]);
    16     for(int i=a.s[0]-1;i>0;i--) printf("%.4d",a.s[i]);
    17 }
    18 STR add(STR &d,STR a,STR b){
    19     int L=max(a.s[0],b.s[0]);
    20     for(int i=1;i<=L;i++){
    21         d.s[i]+=a.s[i]+b.s[i];
    22         d.s[i+1]+=d.s[i]/10000;
    23         d.s[i]%=10000;
    24     }
    25     if(d.s[L+1]) ++L;
    26     d.s[0]=L;
    27     return d;
    28 }
    29 void Inc(STR &a,STR b){
    30     int L=max(a.s[0],b.s[0]);
    31     for(int i=1;i<=L;i++){
    32         a.s[i]+=b.s[i];
    33         a.s[i+1]+=a.s[i]/10000;
    34         a.s[i]%=10000;
    35     }
    36     if(a.s[L+1]) ++L;
    37     a.s[0]=L;
    38 }
    39 STR C(int n,int m){
    40     if(c[n][m].s[0]) return c[n][m];
    41     if(n==m||!m) return c[n][m]=One;
    42     return add(c[n][m],C(n-1,m-1),C(n-1,m));
    43 }
    44 int main(){
    45     One.s[0]=One.s[1]=1;
    46     int k,w;
    47     scanf("%d%d",&k,&w);
    48         int Max=w/k,lim1=1<<k;
    49         --lim1;
    50         for(int i=2;i<=Max;i++) 
    51       if(i<=lim1)
    52         Inc(ans,C(lim1,i));
    53     
    54          int lim2=1<<(w%k);
    55     for(int j=1;j<lim2&&lim1-j>=Max;j++) 
    56        Inc(ans,C(lim1-j,Max));
    57     put(ans);
    58 }
    View Code
  • 相关阅读:
    iscsi-分区类型
    NFS
    测试目录
    测试
    函数
    循环、枚举、条件判断、选择排序
    格式化、列表、元组、字典、集合
    常量、注释、变量、堆栈、数据类型、强制转换
    站点迁移至https://traceless.site/
    CENTOS7 源码安装NGINX
  • 原文地址:https://www.cnblogs.com/Blacko/p/3380675.html
Copyright © 2011-2022 走看看