G - Numbers :
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3987
题目描述:
将
n
n
n分成至多
m
m
m个非负整数,
a
1
a1
a1
a
2
a2
a2
.
.
.
...
...
a
k
ak
ak
(
k
≤
m
)
(k \leq m)
(k≤m),使得
a
1
a1
a1
o
r
or
or
a
2
a2
a2
o
r
or
or
.
.
.
...
...
o
r
or
or
a
k
ak
ak最小。
(
0
≤
n
<
1
0
1000
,
1
≤
m
<
1
0
100
)
(0\leq n<10^{1000}, 1\leq m<10^{100})
(0≤n<101000,1≤m<10100)
输入样例:
5
3 1
3 2
3 3
10000 5
1244 10
输出样例:
3
3
1
2000
125
思路:
对于题目中的
o
r
or
or运算我们首先从二进制出发,不难发现,如果我们分出的数中含有
2
k
2^{k}
2k,那么答案也有
2
k
2^{k}
2k,这就意味着我们可以尽可能多的分出
2
k
2^{k}
2k。那么就是说如果现在存在
m
∗
(
2
k
−
1
)
<
n
m*(2^{k}-1) < n
m∗(2k−1)<n,答案就一定有
2
k
2^{k}
2k这个位,然后贪心的取最多的
2
k
2^{k}
2k更新答案和
n
n
n就好了。
对于大数直接用java就好了,因为zoj有py2.7所以我偷懒就用了py,java写法也是一样的。
import sys
pw = []
base = 1
for i in range(0, 4000):
pw.append(base)
base <<= 1
T = int(input())
for i in range(T):
n, m = map(int, raw_input().split()) #python2.7字符串读入用raw_input()
up, ans = 0, 0
while pw[up] < n:
up += 1
while n and up >= 0:
if (pw[up] - 1) * m < n:
ans += pw[up]
n = max(n - m*pw[up], n % pw[up])
up -= 1
print(ans)
sys.exit(0)