XEZ 的小学作业

220 篇文章 2 订阅
30 篇文章 0 订阅

题目

题目描述
上小学的时候, 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(n107) 堆石子,每一堆的石子数量都在 1 1 1 2 m − 1 2^m-1 2m1 之间,且互不相同。给定 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(n100) 个正整数 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 dibi b i ∣ a i b_i|a_i biai ,求有多少种选择方案可以满足 ∏ d i    2 ≥ ∏ b i \prod d_i^{\;2}\ge\prod b_i di2bi

数据范围与提示
没有给出范围的变量,认为其在 2 31 − 1 2^{31}-1 2311 以内。

思路

典例营

问题即,求 ⨁ 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!×(n2m1) ,容易计算,所以只需要计算异或和为零的数量。

由于 a a a 的范围是 2 m − 1 2^m-1 2m1 以内,所以可以任选,只要取 a n = ⨁ i = 1 n − 1 a i a_n=\bigoplus_{i=1}^{n-1}a_i an=i=1n1ai 就一定可以让异或和为零。反之,如果异或和为零,必然是 a n a_n an 取其他数的异或和。所以前 n − 1 n-1 n1 个数任意生成,让 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=1n1ai=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 n2 个数异或和为零。这又是递归子问题!

如果用 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)=(i1)!×(i12m1)f(i1)(2mi+1)(i1)f(i2)

别忘了要乘 ( 2 m − i + 1 ) (2^m-i+1) (2mi+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)=2m1 ,一个 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 m2631 都是可以的。

训练营

不难发现,当 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 都不再准确了,都变成了线性),不用害怕。

具体的代码实现可能还有些问题。我试着打一下代码,遇到坑再写上来。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值