洛谷P1066 2^k进制数题解--zhengjun

题目描述

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

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

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

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

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

例:设 k = 3 , w = 7 k=3,w=7 。则 r r 是个八进制数( 2 3 = 8 2^3=8 )。由于 w = 7 w=7 ,长度为 7 7 01 01 字符串按 3 3 位一段分,可分为 3 3 段(即 1 , 3 , 3 1,3,3 ,左边第一段只有一个二进制位),则满足条件的八进制数有:

2 2 位数:
高位为 1 1 6 6 个(即 12 , 13 , 14 , 15 , 16 , 17 12,13,14,15,16,17 ),
高位为 2 2 5 5 个,
\cdots
高位为 6 6 1 1 个(即 67 67 )。
6 + 5 + + 1 = 21 6+5+…+1=21 个。

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

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

输入格式

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

输出格式

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

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

输入输出样例

输入 #1 复制
3 7
输出 #1 复制
36

说明/提示

【数据范围】
1 k 9 1\le k \le 9

1 w 3 × 1 0 4 1\le w \le 3\times 10^4

N O I P   2006 NOIP\ 2006 提高组 第四题

思路

首先,可以看出来这是一道组合数学的题目。

那么,我们一起来推一推式子。

以样例为例:

3 7

因为这一个 2 3 2^3 的数转换成谔进制是不能超过 7 7 位的,而 2 3 = 8 = 100 0 ( 2 ) 2^3=8=1000_{(2)}

所以,这样的一位就要可以分成二进制的 k k 位。

例如 2 4 2^4 进制的 1032 1032

一位一位转化

1 ( 16 ) = 000 1 ( 2 ) 1_{(16)}=0001_{(2)}

0 ( 16 ) = 000 0 ( 2 ) 0_{(16)}=0000_{(2)}

3 ( 16 ) = 001 1 ( 2 ) 3_{(16)}=0011_{(2)}

2 ( 16 ) = 001 0 ( 2 ) 2_{(16)}=0010_{(2)}

其实这里的一位一位的就是相当于 10 10 进制下的,因为每一位都不超过 2 k 2^k

所以最后的结果就是这几个谔进制的数写在一起: 0001 , 0000 , 0011 , 0010 ( 0001,0000,0011,0010( 加了个间隔看得清楚 ) )

然后,再回到样例,一个 2 3 2^3 进制的数转换成谔进制最多只能有 7 7 位。

我们刚才知道了, 2 k 2^k 的数每一位就可以转换成 k k 位的谔进制,那么 7 7 位,就可以有 2 2 位,然后剩下 1 1 ,也就是说这个 2 k 2^k 进制的最高位转换成谔进制最多只能是 1 1 ,所以这个 2 k 2^k 进制的数最多只能有 3 3 位,最高位不能超过 1 1

那如果样例是:

3 8

首先,两位是肯定可以有的,然后余下 2 2 位的谔进制,那这个 2 2 位谔进制最多就是 1 1 ( 2 ) 11_{(2)} ,也就是 3 3

这样,如果 w m o d k w\bmod k 余下的是 x x ,那么最高位就不能超过 2 x 1 2^x-1

这样就总结出了:这个 2 k 2^k 进制的数最多只能有 w ÷ k \lceil w\div k\rceil ,这是一个向上取整的符号,第 w ÷ k + 1 \lfloor w\div k\rfloor+1 位不能超过 2 w m o d k 1 2^{w\bmod k}-1

然后就是一个十分简单的组合数。

让我们模拟一遍(还是样例):

  1. 求出位数 w ÷ k = 3 \lceil w\div k\rceil=3 ,第 w ÷ k + 1 = 3 \lfloor w\div k+1\rfloor=3 不能超过 2 w m o d k 1 = 1 2^{w\bmod k}-1=1
  2. 枚举位数:两位,从 0 0 2 k 1 2^k-1 中选 2 2 个,一共有 C 2 k 1 2 C_{2^k-1}^{2}
  3. 继续枚举位数 \cdots 直到 w ÷ k \lfloor w\div k\rfloor
  4. 枚举最高位的数:1,后面的数可选 2 2 2 k 1 2^k-1 ,一共有 C 2 k 2 2 C_{2^k-2}^{2}
  5. 继续枚举最高位的数 \cdots 直到 2 w m o d k 1 = 1 2^{w\bmod k}-1=1
  6. 输出答案

好了,就是这么一个过程,题目中也很清楚,要高精度,高精度的模板可以从高精度模板–zhengjun拿(我就是用这个模板过的)

最后说一句,高精度的除法比较慢,我一开始算 C n m C_n^m 时用了这个公式: n ! m ! ( n m ) ! \cfrac{n!}{m!(n-m)!} ,结果就 T T 掉了。

反正要算 C n m C_n^m n , m n,m 又不大,直接预处理出来放在数组里面用就可以了,用递推公式(不难理解): C n m = C n 1 m 1 + C n 1 m C_n^m=C_{n-1}^{m-1}+C_{n-1}^m 。需要我说吗?

我还是唠一下吧。就是看这第 n n 个数要不要选,如果选了,剩下的可能就是 C n 1 m 1 C_{n-1}{m-1} ,如果不选,就是 C n 1 m C_{n-1}^m

注意一下初始值:

所有的 C n 0 C_n^0 都是 1 1 ,一个也不选就是一种情况。

好了,我太多嘴

我的代码为了简洁,高精度模板自己去高精度模板–zhengjun拿(顺便点个赞),这里就省略掉了。

代码

#include<bits/stdc++.h>
using namespace std;
/*
高精度模板
*/
int k,w;
bign c[512][512];
bign ans;
int main(){
	scanf("%d%d",&k,&w);
	int t=(1<<k)-1,a=(1<<(w%k))-1;//谔进制就用位运算了
	for(int i=0;i<=t;i++){
		c[i][0]=1;//初始化
		for(int j=1;j<=i;j++)
		    c[i][j]=c[i-1][j-1]+c[i-1][j];
	}
	for(int i=2;i<=w/k&&i<=t;i++)ans+=c[t][i];//注意一下边界2:i<=t
	for(int i=1;i<=a&&t-i>=w/k;i++)ans+=c[t-i][w/k];//同样注意边界
	cout<<ans;//我的模板支持输入输出流
	return 0;
}

谢谢–zhengjun

原创文章 115 获赞 118 访问量 6515

猜你喜欢

转载自blog.csdn.net/A_zjzj/article/details/105600766