题目
题目描述
上小学的时候,
A
r
e
x
t
r
e
\sf Arextre
Arextre 接触了
O
I
OI
OI ,并且做了一些简单的作业题。不过年代久远,他忘了当时他随手切的两道题的解法,也不想去回忆,所以请你帮忙打一下代码。
下面附上他当年使用的教材,来帮助你进行代码实现。
【知识桥】你有一只兔子。我又给了你一只兔子。你现在有几只兔子?两只!我们就将这个过程用 1 + 1 = 2 1+1=2 1+1=2 表示。
【典例营】有 n ( n ≤ 1 0 7 ) n(n\le 10^7) n(n≤107) 堆石子,每一堆的石子数量都在 1 1 1 到 2 m − 1 2^m-1 2m−1 之间,且互不相同。给定 n , m n,m n,m ,问有多少种情况使得 n i m \tt nim nim 游戏下先手必胜。答案模 1 0 9 + 7 10^9+7 109+7 。
【训练营】给出 n ( n ≤ 100 ) n(n\le 100) n(n≤100) 个正整数 a i a_i ai ,你需要选出 n n n 个正整数 b i b_i bi 与 n n n 个正整数 d i d_i di 满足 d i ∣ b i d_i|b_i di∣bi 且 b i ∣ a i b_i|a_i bi∣ai ,求有多少种选择方案可以满足 ∏ d i 2 ≥ ∏ b i \prod d_i^{\;2}\ge\prod b_i ∏di2≥∏bi 。
数据范围与提示
没有给出范围的变量,认为其在
2
31
−
1
2^{31}-1
231−1 以内。
思路
典例营
问题即,求 ⨁ i = 1 n a i ≠ 0 \bigoplus_{i=1}^{n}a_i\ne 0 ⨁i=1nai=0 的数量。由于总方案数是 n ! × ( 2 m − 1 n ) n!\times {2^m-1\choose n} n!×(n2m−1) ,容易计算,所以只需要计算异或和为零的数量。
由于 a a a 的范围是 2 m − 1 2^m-1 2m−1 以内,所以可以任选,只要取 a n = ⨁ i = 1 n − 1 a i a_n=\bigoplus_{i=1}^{n-1}a_i an=⨁i=1n−1ai 就一定可以让异或和为零。反之,如果异或和为零,必然是 a n a_n an 取其他数的异或和。所以前 n − 1 n-1 n−1 个数任意生成,让 a n a_n an 擦屁股就完事儿了!仅剩的问题是 a n = 0 a_n=0 an=0 或者 a n = a x ( x ≠ n ) a_n=a_x(x\ne n) an=ax(x=n) 。
对于 a n = 0 a_n=0 an=0 的情况,等价于 ⨁ i = 1 n − 1 a i = 0 \bigoplus_{i=1}^{n-1}a_i=0 ⨁i=1n−1ai=0 ,这不就是一个递归子问题吗?对于 a n = a x ( x ≠ n ) a_n=a_x(x\ne n) an=ax(x=n) 的情况,显然有 ⨁ i ≠ x i < n a i = 0 \bigoplus_{i\ne x}^{i<n}a_i=0 ⨁i=xi<nai=0 ,即除开 a n , a x a_n,a_x an,ax 之外的 n − 2 n-2 n−2 个数异或和为零。这又是递归子问题!
如果用
f
(
i
)
f(i)
f(i) 表示,一共
i
i
i 堆石子时,有多少种情况先手必败,则
f
(
i
)
=
(
i
−
1
)
!
×
(
2
m
−
1
i
−
1
)
−
f
(
i
−
1
)
−
(
2
m
−
i
+
1
)
(
i
−
1
)
⋅
f
(
i
−
2
)
f(i)=(i-1)!\times {2^m-1\choose i-1}-f(i-1)-(2^m-i+1)(i-1)\cdot f(i-2)
f(i)=(i−1)!×(i−12m−1)−f(i−1)−(2m−i+1)(i−1)⋅f(i−2)
别忘了要乘 ( 2 m − i + 1 ) (2^m-i+1) (2m−i+1) 哦,即考虑 a x a_x ax 的每一个取值。
初值 f ( 1 ) = 0 , f ( 2 ) = 2 m − 1 f(1)=0,\;f(2)=2^m-1 f(1)=0,f(2)=2m−1 ,一个 O ( n ) \mathcal O(n) O(n) 的递推即可。其实还有一个 O ( log m ) \mathcal O(\log m) O(logm) 计算 2 m 2^m 2m 的复杂度,不过这太小了。 p . s . p.s. p.s. 让 m ≤ 2 63 − 1 m\le 2^{63}-1 m≤263−1 都是可以的。
训练营
不难发现,当
b
i
b_i
bi 固定时,
∏
d
i
2
>
∏
b
i
\prod d_i^{\;2}>\prod b_i
∏di2>∏bi 与
∏
d
i
2
<
∏
b
i
\prod d_i^{\;2}<\prod b_i
∏di2<∏bi 是 一一对应 的。不信?直接取
d
i
=
b
i
d
i
d_i={b_i\over d_i}
di=dibi 代入即知!所以问题转化为了计算
∏
d
i
2
=
∏
b
i
\prod d_i^{\;2}=\prod b_i
∏di2=∏bi 的情形。
此时,每个质因数是 独立的(独立真是个骚操作啊,皮配也是这种方法),分开考虑。用
f
(
i
,
j
)
f(i,j)
f(i,j) 表示,考虑了前
i
i
i 个数字,
d
d
d 中的指数
−
-
−
b
d
{b\over d}
db 中的指数
=
j
=j
=j 的情况。即,
∏
d
2
b
=
q
p
j
(
q
p
∉
Z
)
\prod {d^2\over b}=qp^j\quad\left({q\over p}\notin \Z\right)
∏bd2=qpj(pq∈/Z)
然后做一个类似背包的东东就可以了。背包容量 O ( n log a ) \mathcal O(n\log a) O(nloga) ,物品数量 O ( n log a ) \mathcal O(n\log a) O(nloga) ,所以总复杂度 O ( n 2 log 2 a ) \mathcal O(n^2\log^2a) O(n2log2a) 。质因数个数一般都很少,最多就 10 10 10 左右(而且此种情形下 log a \log a loga 都不再准确了,都变成了线性),不用害怕。
具体的代码实现可能还有些问题。我试着打一下代码,遇到坑再写上来。