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);
    }
    
  • 相关阅读:
    Spring AOP 详解
    java 线程的几种状态
    Atomic
    ConcurrentHashMap原理分析
    MySQL存储过程详解 mysql 存储过程
    spring-定时器(2)
    spring-定时器(1)
    spring-线程池(3)
    spring-线程池(2)
    spring-线程池(1)
  • 原文地址:https://www.cnblogs.com/alex101/p/14012236.html
Copyright © 2011-2022 走看看