题目描述
设 r r r 是个 2 k 2^k 2k 进制数,并满足以下条件:
- r r r 至少是个 2 2 2 位的 2 k 2^k 2k 进制数。
- 作为 2 k 2^k 2k 进制数,除最后一位外, r r r 的每一位严格小于它右边相邻的那一位。
- 将 r r r 转换为二进制数 q q q 后,则 q q q 的总位数不超过 w w w。
在这里,正整数 k , w k,w k,w 是事先给定的。
问:满足上述条件的不同的 r r r 共有多少个?
我们再从另一角度作些解释:设 S S S 是长度为 w w w 的 01 01 01 字符串(即字符串 S S S 由 w w w 个 0 0 0 或 1 1 1 组成), S S S 对应于上述条件三中的 q q q。将 S S S 从右起划分为若干个长度为 k k k 的段,每段对应一位 2 k 2^k 2k 进制的数,如果 S S S 至少可分成 2 2 2 段,则 S S S 所对应的二进制数又可以转换为上述的 2 k 2^k 2k 进制数 r r r。
例:设 k = 3 , w = 7 k=3,w=7 k=3,w=7。则 r r r 是个八进制数( 2 3 = 8 2^3=8 23=8)。由于 w = 7 w=7 w=7,长度为 7 7 7 的 01 01 01 字符串按 3 3 3 位一段分,可分为 3 3 3 段(即 1 , 3 , 3 1,3,3 1,3,3,左边第一段只有一个二进制位),则满足条件的八进制数有:
2
2
2 位数:
高位为
1
1
1:
6
6
6 个(即
12
,
13
,
14
,
15
,
16
,
17
12,13,14,15,16,17
12,13,14,15,16,17),
高位为
2
2
2:
5
5
5 个,
⋯
\cdots
⋯,
高位为
6
6
6:
1
1
1 个(即
67
67
67 )。
共
6
+
5
+
…
+
1
=
21
6+5+…+1=21
6+5+…+1=21 个。
3
3
3 位数:
高位只能是
1
1
1,
第
2
2
2 位为
2
2
2:
5
5
5 个(即
123
,
124
,
125
,
126
,
127
123,124,125,126,127
123,124,125,126,127),
第
2
2
2 位为
3
3
3:
4
4
4 个,
⋯
\cdots
⋯,
第
2
2
2 位为
6
6
6:
1
1
1 个(即
167
167
167)。
共
5
+
4
+
…
+
1
=
15
5+4+…+1=15
5+4+…+1=15 个。
所以,满足要求的 r r r 共有 36 36 36 个。
输入格式
一行两个正整数 k , w k,w k,w 用一个空格隔开:
输出格式
一行一个个正整数,为所求的计算结果。
即满足条件的不同的
r
r
r 的个数(用十进制数表示),要求不得有前导零,各数字之间不得插入数字以外的其他字符(例如空格、换行符、逗号等)。
(提示:作为结果的正整数可能很大,但不会超过 200 200 200 位)
输入输出样例
输入 #1 复制
3 7
输出 #1 复制
36
说明/提示
【数据范围】
1
≤
k
≤
9
1\le k \le 9
1≤k≤9
1 ≤ w ≤ 3 × 1 0 4 1\le w \le 3\times 10^4 1≤w≤3×104
N O I P 2006 NOIP\ 2006 NOIP 2006 提高组 第四题
思路
首先,可以看出来这是一道组合数学的题目。
那么,我们一起来推一推式子。
以样例为例:
3 7
因为这一个 2 3 2^3 23的数转换成谔进制是不能超过 7 7 7位的,而 2 3 = 8 = 100 0 ( 2 ) 2^3=8=1000_{(2)} 23=8=1000(2)
所以,这样的一位就要可以分成二进制的 k k k位。
例如 2 4 2^4 24进制的 1032 1032 1032。
一位一位转化
1 ( 16 ) = 000 1 ( 2 ) 1_{(16)}=0001_{(2)} 1(16)=0001(2)
0 ( 16 ) = 000 0 ( 2 ) 0_{(16)}=0000_{(2)} 0(16)=0000(2)
3 ( 16 ) = 001 1 ( 2 ) 3_{(16)}=0011_{(2)} 3(16)=0011(2)
2 ( 16 ) = 001 0 ( 2 ) 2_{(16)}=0010_{(2)} 2(16)=0010(2)
其实这里的一位一位的就是相当于 10 10 10进制下的,因为每一位都不超过 2 k 2^k 2k。
所以最后的结果就是这几个谔进制的数写在一起: 0001 , 0000 , 0011 , 0010 ( 0001,0000,0011,0010( 0001,0000,0011,0010(加了个间隔看得清楚 ) ) )。
然后,再回到样例,一个 2 3 2^3 23进制的数转换成谔进制最多只能有 7 7 7位。
我们刚才知道了, 2 k 2^k 2k的数每一位就可以转换成 k k k位的谔进制,那么 7 7 7位,就可以有 2 2 2位,然后剩下 1 1 1,也就是说这个 2 k 2^k 2k进制的最高位转换成谔进制最多只能是 1 1 1,所以这个 2 k 2^k 2k进制的数最多只能有 3 3 3位,最高位不能超过 1 1 1。
那如果样例是:
3 8
首先,两位是肯定可以有的,然后余下 2 2 2位的谔进制,那这个 2 2 2位谔进制最多就是 1 1 ( 2 ) 11_{(2)} 11(2),也就是 3 3 3。
这样,如果 w m o d k w\bmod k wmodk余下的是 x x x,那么最高位就不能超过 2 x − 1 2^x-1 2x−1
这样就总结出了:这个 2 k 2^k 2k进制的数最多只能有 ⌈ w ÷ k ⌉ \lceil w\div k\rceil ⌈w÷k⌉,这是一个向上取整的符号,第 ⌊ w ÷ k ⌋ + 1 \lfloor w\div k\rfloor+1 ⌊w÷k⌋+1位不能超过 2 w m o d k − 1 2^{w\bmod k}-1 2wmodk−1。
然后就是一个十分简单的组合数。
让我们模拟一遍(还是样例):
- 求出位数 ⌈ w ÷ k ⌉ = 3 \lceil w\div k\rceil=3 ⌈w÷k⌉=3,第 ⌊ w ÷ k + 1 ⌋ = 3 \lfloor w\div k+1\rfloor=3 ⌊w÷k+1⌋=3不能超过 2 w m o d k − 1 = 1 2^{w\bmod k}-1=1 2wmodk−1=1。
- 枚举位数:两位,从 0 0 0到 2 k − 1 2^k-1 2k−1中选 2 2 2个,一共有 C 2 k − 1 2 C_{2^k-1}^{2} C2k−12
- 继续枚举位数 ⋯ \cdots ⋯直到 ⌊ w ÷ k ⌋ \lfloor w\div k\rfloor ⌊w÷k⌋
- 枚举最高位的数:1,后面的数可选 2 2 2到 2 k − 1 2^k-1 2k−1,一共有 C 2 k − 2 2 C_{2^k-2}^{2} C2k−22
- 继续枚举最高位的数 ⋯ \cdots ⋯直到 2 w m o d k − 1 = 1 2^{w\bmod k}-1=1 2wmodk−1=1
- 输出答案
好了,就是这么一个过程,题目中也很清楚,要高精度,高精度的模板可以从高精度模板–zhengjun拿(我就是用这个模板过的)
最后说一句,高精度的除法比较慢,我一开始算 C n m C_n^m Cnm时用了这个公式: n ! m ! ( n − m ) ! \cfrac{n!}{m!(n-m)!} m!(n−m)!n!,结果就 T T T掉了。
反正要算 C n m C_n^m Cnm, 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 Cnm=Cn−1m−1+Cn−1m。需要我说吗?
我还是唠一下吧。就是看这第 n n n个数要不要选,如果选了,剩下的可能就是 C n − 1 m − 1 C_{n-1}{m-1} Cn−1m−1,如果不选,就是 C n − 1 m C_{n-1}^m Cn−1m。
注意一下初始值:
所有的 C n 0 C_n^0 Cn0都是 1 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;
}