解题思路:
这个题用了一天的时间,看各种大神写的,然后最后找到了一个比较简单且易懂的方式分享给大家,这个题我也不会做,不过学到了点新知识。


思路: 这是一个组合数学问题,

注意这句话:作为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)

所以上述两者相加便是正解(需要高精运算)


对于高精运算的处理,我看到了一个比较巧妙的方法避开了复杂的数组运算,就是把上面那些组合数的运算

都转换成了    C(2^k-1,i) ----->  C(2^k-i,i)    然后写C函数的时候不是计算C(2^k-1,i),而是计算C(2^k-i+i-1,i)。  巧妙之处就在这里,这样可以有效的避免有溢出吧。 


注意事项:
1、本题的关键就是看懂题目,知道这是个排列组合问题。

2、在排列组合的计算时,用了一个巧妙的方法,希望能看懂。


参考代码:

#include <iostream>

#include <cmath>

using namespace std;


long C(int n,int m)                 //公式为C(n+m-1)(m)[重点]   希望结合上面说的看懂

{

    int i;

    long sum=1;

    for (i=1;i<=m;i++)

        sum*=(n+m-i);

    for (i=1;i<=m;i++)

        sum=sum/i;

    return sum;

}


int main()

{

    int k, w;

    cin >> k >> w;


    int part_num = w / k + 1;             //一共分为几段

    int maxx_num_per_part = pow(2.0,k);             //取不到,每部分最大取到maxx_num_per_part减去1,就是每一位都是1的时候

    int gaow_num_max = pow(2.0,w%k) - 1;         //最高位的数最大值,可以是0


    //开始计算,分两种情况,第一种,首段为0,那么后面n位数对应的个数符合C[maxx_num_per_part-1][n]

    long long sum = 0;

    for (int i=2; i<=part_num-1; i++)           //去掉最高位部分,还有至少两位数

    {

        sum += C(maxx_num_per_part-i, i);

    }


    //第二种情况,首段不是0,如果首段为x,解就有C[maxx_num_per_part-1-x][w/k]


    for (int i=1; i<=gaow_num_max; i++)

    {

        sum += C(maxx_num_per_part-w/k-i,w/k);

    }


    cout << sum;

    return 0;

}


点赞(6)
 

0.0分

5 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 4 条评论

van之风 4年前 回复TA
解释不清楚就不要写解释。。。。。中间有一段误人子弟了
凸哔男勃丸 4年前 回复TA
秒啊
一条咸鱼 4年前 回复TA
@sususu352 ”作为结果的正整数可能很大,但不会超过200位“题目中的原话,200位整数远远超过int和long long的取值范围,所以叫高精度
sususu352 5年前 回复TA
那个高精度是什么意思。。没有看懂