【洛谷5363】[SDOI2019] 移动金币(动态规划)
大致题意: 有\(n\)个格子,让你摆放\(m\)个金币。二人博弈,每次选择一个金币向左移任意格,无法移动者输。问有多少种方案使先手必胜。
阶梯\(Nim\)
阶梯\(Nim\)的基本模型,就是有\(n\)层楼梯(从\(0\sim n-1\)编号),每层楼梯上有若干石子,每次可以取任一层楼梯上任意多个石子到下一层,无法移动者输。
它的解决方法就是,去掉所有编号为偶数的楼梯,然后对剩下的这些编号为奇数的楼梯当成普通\(Nim\)来做。
原理是,如果一人移动编号为偶数的楼梯上的石子到下一层,如移动第\(2n\)层的\(a\)个石子到第\(2n-1\)层,那么无论何时对方都可以把这\(a\)个石子接着从第\(2n-1\)层移动到第\(2n-2\)层,因为\(2n-2\)层是必然存在的。
所以,移动偶数层的石子相当于是无效的,就可以直接忽略。
此题转化
对于这道题,我们可以发现,如果把每两个金币之间的空格当作一堆石子,这就是一个典型的阶梯\(Nim\)。
也就是说,若要先手必胜,就要满足奇数堆石子个数异或值不为\(0\)。
这显然不好求,所以我们可以转而求异或值为\(0\)的方案数,再用总方案数\(C_n^m\)减去它即为答案。
动态规划
考虑如何求异或值为\(0\)的方案数。
可以在二进制下逐位\(DP\)。
我们设\(f_{i,j}\)表示满足二进制下从最高位至右数第\(i\)位异或值为\(0\),剩余石子总数为\(j\)的方案数。
那么对于\(f_{i,j}\)的转移,我们可以枚举有\(k\)个奇数堆石子个数二进制下第\(i\)位为\(1\),其中因为要使异或值为\(0\),因此\(k\)为偶数。
转移方程为:
\]
其中\(t1\)表示奇数堆的个数。
计算答案
我们可以枚举满足所有奇数堆每一位异或值为\(0\)时所剩的石子个数\(i\),这就是偶数堆的石子个数。
则用插板法就可以求出异或值为\(0\)的方案数为:
\]
其中\(t0\)表示偶数堆的个数。
最后用\(C_n^m\)减去这一方案数就是答案。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 150000
#define M 50
#define LN 20
#define X 1000000009
#define Qinv(x) Qpow(x,X-2)
#define C(x,y) (1LL*Fac[x]*IFac[y]%X*IFac[(x)-(y)]%X)//组合数
using namespace std;
int n,m,Fac[N+5],IFac[N+5],f[LN+5][N+5];
I int Qpow(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
int main()
{
RI i,j,k,t0,t1,res=0;scanf("%d%d",&n,&m),t0=(m>>1)+1,t1=m+1>>1;//计算偶数堆和奇数堆个数
for(k=max(n,2*m),Fac[0]=i=1;i<=k;++i) Fac[i]=1LL*Fac[i-1]*i%X;//初始化阶乘
for(IFac[k]=Qinv(Fac[k]),i=k-1;~i;--i) IFac[i]=1LL*IFac[i+1]*(i+1)%X;//初始化阶乘逆元
for(f[LN][n-m]=1,i=LN-1;~i;--i) for(j=0;j<=n-m;++j)//动态规划
for(k=0;k<=t1&&j+(k<<i)<=n-m;k+=2) f[i][j]=(C(t1,k)*f[i+1][j+(k<<i)]+f[i][j])%X;
for(i=0;i<=n-m;++i) res=(C(i+t0-1,t0-1)*f[0][i]+res)%X;//计算异或值为0的方案数
return printf("%d",(C(n,m)-res+X)%X),0;//输出答案
}
【洛谷5363】[SDOI2019] 移动金币(动态规划)的更多相关文章
- BZOJ4553/洛谷P4093 [HEOI2016/TJOI2016]序列 动态规划 分治
原文链接http://www.cnblogs.com/zhouzhendong/p/8672434.html 题目传送门 - BZOJ4553 题目传送门 - 洛谷P4093 题解 设$Li$表示第$ ...
- 随手练——洛谷-P1002 过河卒(动态规划入门)
题目链接:https://www.luogu.org/problemnew/show/P1002 题目还算良心,提醒了结果可能很大,确实爆了int范围, 这是一开始写的版本,用递归做的,先给地图做标记 ...
- 【洛谷】P2694 接金币(排序)
题目描述 在二维坐标系里,有N个金币,编号0至N-1.初始时,第i个金币的坐标是(Xi,Yi).所有的金币每秒向下垂直下降一个单位高度,例如有个金币当前坐标是(xf, yf),那么t秒后金币所在的位置 ...
- 洛谷P1002 过河卒 题解 动态规划
题目链接:https://www.luogu.com.cn/problem/P1002 题目大意 棋盘上\(A\)点有一个过河卒,需要走到目标\(B\)点.卒行走的规则:可以向下.或者向右.同时在棋盘 ...
- 洛谷P5774,可爱的动态规划。
如此可爱的动态规划见过么? 相信各位都非常喜欢动态规划,那我就写一道可爱的动态规划的题解吧. 题目:https://www.luogu.com.cn/problem/P5774 题意: 题意“挺明白” ...
- 洛谷P1028.数的计算(动态规划)
题目描述 我们要求找出具有下列性质数的个数(包含输入的自然数n): 先输入一个自然数n(n≤1000),然后对此自然数按照如下方法进行处理: 1.不作任何处理; 2.在它的左边加上一个自然数,但该自然 ...
- [洛谷P3878][TJOI2010]分金币
题目大意:把$n(n\leqslant30)$个数分成两组,两组个数最多相差$1$,求出两组元素差的绝对值最小使多少 题解:模拟退火 卡点:$\exp$中的两个数相减写反,导致$\exp(x)$中的$ ...
- [洛谷P5361][SDOI2019]热闹又尴尬的聚会:构造题
分析 构造方法 (截图自UOJ群) 可以使用std::set维护这个过程,不过据说可以做到\(O(n+m)\).. 正确性证明 题目中的要求等价于\((p+1)(q+1) > n\) 设每次找出 ...
- 洛谷P1002 过河卒(动态规划)
题目描述 棋盘上 AA 点有一个过河卒,需要走到目标 BB 点.卒行走的规则:可以向下.或者向右.同时在棋盘上 CC 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点.因此称之为 ...
随机推荐
- c#串口通信并处理接收的多个参数
最近摸索做个上位机,简单记录一下关键的几个部分 c#做串口通信主要使用的是System.IO.Ports类,其实还是十分方便的 最终效果如下: 千万不要忘记了下面这个 填写串口相关配置 我们可以通过G ...
- 使用 Anydesk 5.1 TCP 通道(端口映射)功能从外网方便访问内网的 web/数据库等资源
Anydesk 5.1 带来一个新的功能:TCP 通道,在家办公时,通过互联网进行远程桌面连接到公司电脑,可以将家用电脑的某个端口,映射到公司网络的某个电脑( IP + 端口),不局限于被远程桌面连接 ...
- 拥抱自动化,CODING 2.0 持续集成全新上线
在文章开始前,做一个小调查,在您的软件项目中集成一行新代码平均需要花多长时间? 15 分钟 一小时 半天 一天及以上 注意这里的集成是指将源码放在一起,并验证源码可以作为一个一致.运行可靠的软件的过程 ...
- vim简单操作命令
vim简单操作命令: 开启编辑:按“i”或者“Insert”键 退出编辑:“Esc”键 退出vim:“:q” 保存vim:“:w” 保存退出vim:“:wq” 不保存退出vim:“:q!” 查看当前系 ...
- PHP计算二维数组指定元素的和
array_sum(array_column($arr, 'num')); //计算二维数组指定元素的和 $arr = [ [ 'id'=>1, 'num'=>3, ], [ 'id'=& ...
- Mysql模式匹配两种方法
一.使用LIKE或NOT LIKE比较操作符 使用 "_" 匹配任何单个字符,而 "%" 匹配任意数量的字符(包括零字符): 例如: 1.要想找出以“b”开头的 ...
- 在 Cocos2d-x 中添加自己的微博链接
配置:OS X 10.10 + Xcode 6.0 + Cocos2d-x-3.2 一.Android 端代码 1.在 Cocos2dxActivity.java 中添加openUrl函数并导入响应包 ...
- react生命周期函数的应用-----1性能优化 2发ajax请求
知识点1:每次render其实就会将jax的模板生成一个虚拟dom,跟上一个虚拟dom进行比对,通过diff算法找出不同,再更新到真实dom上去. 1性能优化 每次父组件render一次(除了第一次初 ...
- redis为什么是单线程而且速度快?
redis支持的5种数据类型: 1.String(字符串) 2.List(数组或列表) 3.Set(集合) 4.Hash(哈希或字典) 5.ZSet(有序集合) 数据库的工作模式按存储方式可分为: 硬 ...
- 如何编写高质量的 JS 函数(4) --函数式编程[实战篇]
本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/ZoXYbjuezOWgNyJKmSQmTw作者:杨昆 [编写高质量函数系列],往期精彩内容: ...