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

    P1066 2^k进制数

    题目链接

    题目描述

    设 r 是个 2^k进制数,并满足以下条件:

    • r 至少是个 2 位的 2^k进制数。
    • 作为 2^k进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位。
    • 将 r转换为二进制数 q后,则 q的总位数不超过 w。

    在这里,正整数 k,w 是事先给定的。

    问:满足上述条件的不同的 r共有多少个?

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

    例:设 k=3,w=7 k =3。则 r 是个八进制数( 2^3=8 )。由于 w=7,长度为 7 的 01 字符串按 33位一段分,可分为 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 个。

    输入格式

    一行两个正整数 k,w 用一个空格隔开:

    输出格式

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

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

    解析

    首先我们来理解题意,r为k进制数,转化为二进制后,01串最多位不能超过w。由于k位01串可以组成一个k进制数,我们不妨将最多位可能的情况下的w按k位一组进行切分,得到L = ceil(w/k)组,那么r在k进制情况下最多有L位,最少有2位。

    例如输入3,7时,r位8进制数,r的每位由3个二进制位构成,r最多情况下可能由7个二进制位构成。我们将7按3位一组进行切分,得到[1,3,3]。

    r在k进制下最少只有两位,最多L位,则r的所有情况为 2位r下的情况到L位r下的情况总数之和。

    以 3 7为例,则r可能有2位或3位,当r两位的时候,可能情况有 12,13,14,..17,23,24..27,67,即在1..7的数字中选择2个,构成二位的r。当r三位时,即首先选择出第一位,并在剩下的位中选择出2个比第一位大的数。

    由此,可以看出这个问题实际上是组合数问题。

    当前n个分段,每个分段均为k位时,则每段可选择的数字为2k-1,而r的可能情况为(2k-1)中取i位(i从2到n)

    最后一个分段有可能不到k位,则首先从1开始选择,做出第一次选择后,计算出剩下n-1个分段的组合数,并依次求和,得到最终结果。

    接下来问题就转换到如何计算组合数了。

    计算组合数可以参考这篇博文 参考链接

    此处使用杨辉三角递推求解组合数值。

    最后本题中会出现大整数,超出 long long int范围,因此对于C++/C实现来说需要手写大整数

    在此首先给出Java版本代码

    
    
    import java.math.BigInteger;
    import java.util.ArrayList;
    import java.util.Scanner;
    
    public class Main {
        private static final int n = 1000;
        static BigInteger [][]comb = new BigInteger[1000][1000];
        static void init()
        {
            for(int i=0;i<n ;i++)
            {
                comb[i][0] = BigInteger.valueOf(1);
                comb[i][i] = BigInteger.valueOf(1);
                for(int j=1;j<i;j++)
                {
                    comb[i][j] = comb[i-1][j].add(comb[i-1][j-1]);
                }
            }
    
        }
    
    
        static BigInteger C(int n, int m)
        {
            if(n<m) return BigInteger.valueOf(0);
            return comb[n][m];
        }
    
        public static void main(String[] args) {
            BigInteger cnt =BigInteger.valueOf(0);
            init();
            int k,w;
            Scanner in = new Scanner(System.in);
            k = in.nextInt();
            w = in.nextInt();
            int fullPart = w / k;
            int divPart = (int) Math.ceil(1.0*w / k);
            int resPart = 0;
            if (w % k != 0)
            {
                resPart = (int) (w - k * fullPart);
            }
            int sel = (int) (Math.pow(2, k) - 1);
            for (int i = 2; i <= divPart; i++)
            {
                if (i != divPart)
                {
                    cnt = cnt.add(C(sel,i));
                }
                else
                {
                    if (resPart != 0)
                    {
                        int t = (int) (Math.pow(2, resPart) - 1);
                        for (int j = 1; j <= t; j++)
                        {
                            cnt = cnt.add(C(sel-j,i-1));
                        }
                    }
                    else
                    {
                        cnt = cnt.add(C(sel,i));
                    }
                }
    
            }
            System.out.println(cnt);
        }
    }
    

    C语言代码 此处大整数代码来自于其他博文,一时找不到出处

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #define ll long long int
    #define maxChar 130
    #define maxlen 260
    typedef struct HP
    {int len;
    char s[maxChar];
    }HP;
    void PrintHP(HP x) {for(int i=x.len;i>=1;i--) printf("%d",x.s[i]);}
    void Str2HP(const char *s,HP *x)
    {
    	x->len=strlen(s);
    	for(int i=1;i<=x->len;i++) x->s[i]=s[x->len-i]-'0'; //倒着记录
    }
    void Plus(const HP a,const HP b,HP*c)
    {
    	int i;c->s[1]=0;
    	for(i=1;i<=a.len||i<=b.len||c->s[i];i++){
    		if(i<=a.len) c->s[i]+=a.s[i];
    		if(i<=b.len) c->s[i]+=b.s[i];
    		c->s[i+1]=c->s[i]/10;c->s[i]%=10;
    	}
    	c->len=i-1;if(c->len==0) c->len=1;
    }
    HP comb[maxlen][maxlen];
    void init()
    {
            for(int i=0;i<maxlen ;i++)
            {
                
                Str2HP("1",&comb[i][0]);
                Str2HP("1",&comb[i][i]);
                for(int j=1;j<i;j++)
                {
                    Plus(comb[i-1][j],comb[i-1][j-1],&comb[i][j]);
                }
            }
    }
    HP C(ll n, ll m)
    {
        HP t;
        Str2HP("0",&t);
        if(n<m) return t;
        return comb[n][m];
    }
    
    int main()
    {
        HP ans;
        HP temp;
        ll cnt = 0;
        Str2HP("0",&ans);
        ll k, w;
        init();
        scanf("%lld %lld", &k, &w);
        ll fullPart = w / k;
        ll divPart = ceil(1.0*w / k);
        int resPart = 0;
        if (w % k != 0)
            resPart = w - k * fullPart;
        int sel = pow(2, k) - 1;
        for (int i = 2; i <= divPart; i++)
        {
            if (i != divPart)
            {
                HP t=  C(sel,i);
                HP a = ans;
                Plus(a,t,&ans);
            }
            else
            {
                if (resPart != 0)
                {
                    int t = pow(2, resPart) - 1;
                    for (int j = 1; j <= t; j++)
                    {
                        HP x = C(sel - j, (i - 1));
                        HP a = ans;
                        Plus(a,x,&ans);
                    }
                }
                else
                {
                    HP x = C(sel, i);
                    HP a = ans;
                    Plus(a,x,&ans);
                }
    
            }
    
        }
        PrintHP(ans);
    }
    
  • 相关阅读:
    数据库表结构变动发邮件脚本
    .net程序打包部署
    无法登陆GitHub解决方法
    netbeans 打包生成 jar
    第一次值班
    RHEL6 纯命令行文本界面下安装桌面
    C语言中格式化输出,四舍五入类型问题
    I'm up to my ears
    How to boot ubuntu in text mode instead of graphical(X) mode
    the IP routing table under linux@school
  • 原文地址:https://www.cnblogs.com/alex101/p/14012236.html
Copyright © 2011-2022 走看看