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);
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 数据类型 基本数据类型 数字(Number) 整型(int) 整数类型共有4种进制表示:十进制、二进制、八进制和十...
    柄志阅读 2,151评论 0 0
  • 第一部分 初识Python语言 第1章 程序设计基本方法 1.1 计算机的概念 计算机是根据指令操作数据的设备,具...
    不脱发的程序员阅读 1,083评论 0 1
  • 关于数据的存储结构,以下选项描述正确的是( D )A: 数据所占的存储空间量B: 存储在外存中的数据C: 数据在计...
    IIronMan阅读 136,068评论 7 60
  • 基于《Python语言程序设计基础(第2版)》 第一部分 初识Python语言 第1章 程序设计基本方法 1.1 ...
    柄志阅读 27,317评论 4 44
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,475评论 16 22