当前位置: 首页 > news >正文

【PE806】Nim on Towers of Hanoi(DP)(生成函数)

Nim on Towers of Hanoi

题目链接:PE806

题目大意

一个有 n 个盘子的汉诺塔,在第 i 个状态的时候如果三个柱子的盘子个数的异或和是 0,就会给 i 的贡献。
求 n=100000 时候的贡献和。

思路

发现这个给贡献很难搞,因为你几乎很难确定它是在第几步。
但是发现这个很诺塔它有一个对称性,也就是把第 i i i 个状态的两边的柱子换一下位置,就是第 2 n − 1 − i 2^n-1-i 2n1i 个状态了。

这个有什么用呢?因为是异或,所以如果 i i i 满足, 2 n − 1 − i 2^n-1-i 2n1i 也满足。
所以我们只需要求出满足的个数 k k k,答案就是 k ( 2 n − 1 ) 2 \dfrac{k(2^n-1)}{2} 2k(2n1)

于是问题变成求 k k k,条件是 a + b + c = 0 , a ⊕ b ⊕ c = 0 a+b+c=0,a\oplus b\oplus c=0 a+b+c=0,abc=0
会发现如果 n n n 的某一位是 1 1 1,它一定要拆成比它第一位的两个数(所以奇数没有解)。
那分配给那两个呢?有 3 3 3 种选择的。
所以满足条件的 a , b , c a,b,c a,b,c 的情况个数就是 3 p o p c o u n t ( n ) 3^{{\rm popcount}(n)} 3popcount(n)

看起来挺多,但是 n n n p o p c o u n t ( n ) = 6 {\rm popcount}(n)=6 popcount(n)=6,所以其实很少。
但是问题是,一个 a , b , c a,b,c a,b,c 不一定只对应一种情况,所以你还要看一个三元组 ( a , b , c ) (a,b,c) (a,b,c) 对应多少方案。
设为 f i , j , k f_{i,j,k} fi,j,k,生成函数的话就是 F ( x , y , z ) F(x,y,z) F(x,y,z)
(由于对称你有 f i , j , k = f k , j , i f_{i,j,k}=f_{k,j,i} fi,j,k=fk,j,i

考虑怎么 DP,然后你每次考虑多一个最大的圆盘。
那应该是把上面的一坨丢到第二个碟子,然后把最小面的丢过去,然后再把第二个柱子那一坨再扔到第三个柱子。
那中间的两个过程都会分别给贡献,所以你最大的柱子可以放在第一个柱子的最下面,也可以放在第三个柱子的最小面,分别会给贡献。
那就要看上面那坨是怎样的,所以有这样的转移:
( x − 1 , z , y ) → ( x , y , z ) (x-1,z,y)\rightarrow(x,y,z) (x1,z,y)(x,y,z)(上面那坨先到第三个,再到第二个)
( y , z , x − 1 ) → ( x , y , z ) (y,z,x-1)\rightarrow(x,y,z) (y,z,x1)(x,y,z)(上面的步骤反过来)
那在生成函数上:
F ( x , y , z ) = 1 + x F ( x , z , y ) + x F ( y , z , x ) F(x,y,z)=1+xF(x,z,y)+xF(y,z,x) F(x,y,z)=1+xF(x,z,y)+xF(y,z,x) 1 1 1 是修正项)
然后由于 F ( x , y , z ) = F ( z , y , x ) F(x,y,z)=F(z,y,x) F(x,y,z)=F(z,y,x),我们用中间的做标志,设为 F y F_y Fy

然后可以得到三个式子:
F x = 1 + z F y + y F z F_x=1+zF_y+yF_z Fx=1+zFy+yFz
F y = 1 + z F x + x F z F_y=1+zF_x+xF_z Fy=1+zFx+xFz
F z = 1 + y F x + x F y F_z=1+yF_x+xF_y Fz=1+yFx+xFy
解方程可以得到三个的表示,我们只需要用到 F y F_y Fy
F y = ( 1 + y ) ( 1 + x + z − y ) 1 − x 2 − y 2 − z 2 − 2 x y z F_y=\dfrac{(1+y)(1+x+z-y)}{1-x^2-y^2-z^2-2xyz} Fy=1x2y2z22xyz(1+y)(1+x+zy)

那我们只需要取它 [ x a y b z c ] [x^ay^bz^c] [xaybzc] 项的系数即可!

考虑上面的拆开每个系数分开算,下面的话我们设 p = x 2 + y 2 + z 2 + 2 x y z p=x^2+y^2+z^2+2xyz p=x2+y2+z2+2xyz
那下面的 1 1 − p = 1 + p + p 2 + . . . \dfrac{1}{1-p}=1+p+p^2+... 1p1=1+p+p2+...
然后我们看到只有一个有多元,考虑枚举它的个数,那剩下三个用多少次也就固定了,组合数安排一下顺序就能求。

那我们看看复杂度,上面枚举 ( a , b , c ) (a,b,c) (a,b,c) 3 p o p c o u n t ( n ) 3^{{\rm popcount(n)}} 3popcount(n),这里算有一个 2 × 4 2\times 4 2×4 的常数(上面的系数每个都要),然后里面再一个 n n n,所以复杂度是 3 p o p c o u n t ( n ) n 3^{{\rm popcount(n)}}n 3popcount(n)n,在 n = 100000 n=100000 n=100000 的时候 p o p c o u n t ( n ) = 6 {\rm popcount(n)}=6 popcount(n)=6,跑的很快。

代码

#include<cstdio>
#include<iostream>
#define mo 1000000007

using namespace std;

const int N = 1e5 + 100;
int n = 100000, ans;
int xl[10], jc[N], inv[N], invs[N];

int add(int x, int y) {return x + y >= mo ? x + y - mo : x + y;}
int dec(int x, int y) {return x < y ? x - y + mo : x - y;}
int mul(int x, int y) {return 1ll * x * y % mo;}
int ksm(int x, int y) {int re = 1; while (y) {if (y & 1) re = mul(re, x); x = mul(x, x); y >>= 1;} return re;}

int slove_(int a, int b, int c) {
	if (a < 0 || b < 0 || c < 0) return 0;
	if (((a & 1) ^ (b & 1)) || ((a & 1) ^ (c & 1))) return 0;
	int ans = 0;
	for (int i = 0, di = 1; i <= min(min(a, b), c); i++, di = mul(di, 2)) {
		if ((a - i) & 1) continue;
		int n = (a - i + b - i + c - i) / 2 + i;
		ans = add(ans, mul(di, mul(jc[n], mul(invs[i], mul(invs[(a - i) / 2], mul(invs[(b - i) / 2], invs[(c - i) / 2]))))));
	}
	return ans;
}

int slove(int a, int b, int c) {
	int ans = 0;
	ans = add(ans, slove_(a, b, c));
	ans = add(ans, slove_(a - 1, b, c));
	ans = add(ans, slove_(a, b, c - 1));
	ans = dec(ans, slove_(a, b - 1, c));
	ans = add(ans, slove_(a, b - 1, c));
	ans = add(ans, slove_(a - 1, b - 1, c));
	ans = add(ans, slove_(a, b - 1, c - 1));
	ans = dec(ans, slove_(a, b - 2, c));
	return ans;
} 

void dfs(int now, int a, int b, int c) {
	if (now > xl[0]) {
		ans = add(ans, slove(a, b, c));
		return ;
	}
	dfs(now + 1, a + (1 << (xl[now] - 1)), b + (1 << (xl[now] - 1)), c);
	dfs(now + 1, a + (1 << (xl[now] - 1)), b, c + (1 << (xl[now] - 1)));
	dfs(now + 1, a, b + (1 << (xl[now] - 1)), c + (1 << (xl[now] - 1)));
}

int main() {
	jc[0] = 1; for (int i = 1; i < N; i++) jc[i] = mul(jc[i - 1], i);
	inv[0] = inv[1] = 1; for (int i = 2; i < N; i++) inv[i] = mul(inv[mo % i], mo - mo / i);
	invs[0] = 1; for (int i = 1; i < N; i++) invs[i] = mul(invs[i - 1], inv[i]);
	
	if (n & 1) {printf("0"); return 0;}
	for (int i = 0; i <= 20; i++)
		if ((n >> i) & 1) xl[++xl[0]] = i;
	dfs(1, 0, 0, 0);
	
	int val = dec(ksm(2, n), 1);
	printf("%d", mul(mul(ans, val), (mo + 1) / 2));
	
	return 0;
}

答案自己编译一下就有。

相关文章:

  • FFmpeg工具使用总结
  • 打电话用蓝牙耳机什么牌子好?打电话清晰的蓝牙耳机推荐
  • OpenAI 开源语音识别 Whisper
  • 陈齐彦:云原生,抵达元宇宙的数字基石
  • WEB自动化测试(1)—— Cypress 介绍
  • C#把数据库表里简体字转化为繁体字
  • JAVA计算机毕业设计云音乐后端内容管理系统Mybatis+系统+数据库+调试部署
  • Vue基础之插槽、自定义指令、render函数、过滤器
  • 企业实践开源的动机
  • 【力扣刷题】Day06——哈希表专题
  • 【web】计算机网络编程(重点:UDP数据报/TCP流套接字编程)
  • img2col 卷积优化讲解
  • 微服务SpringBoot+Neo4j搭建企业级分布式应用拓扑图
  • 简述你对RPC、RMI的理解
  • 召回侧对齐精排的多目标打分融合
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • 4个实用的微服务测试策略
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • C学习-枚举(九)
  • ES6语法详解(一)
  • JavaScript设计模式与开发实践系列之策略模式
  • js中forEach回调同异步问题
  • python 学习笔记 - Queue Pipes,进程间通讯
  • Vue官网教程学习过程中值得记录的一些事情
  • Zepto.js源码学习之二
  • 利用DataURL技术在网页上显示图片
  • 你真的知道 == 和 equals 的区别吗?
  • 突破自己的技术思维
  • ​VRRP 虚拟路由冗余协议(华为)
  • #FPGA(基础知识)
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • ( )的作用是将计算机中的信息传送给用户,计算机应用基础 吉大15春学期《计算机应用基础》在线作业二及答案...
  • (Java数据结构)ArrayList
  • (二)hibernate配置管理
  • (附源码)springboot人体健康检测微信小程序 毕业设计 012142
  • (附源码)ssm高校实验室 毕业设计 800008
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .NET Core、DNX、DNU、DNVM、MVC6学习资料
  • .NET6 命令行启动及发布单个Exe文件
  • .NET设计模式(2):单件模式(Singleton Pattern)
  • .NET业务框架的构建
  • .Net组件程序设计之线程、并发管理(一)
  • @KafkaListener注解详解(一)| 常用参数详解
  • @zabbix数据库历史与趋势数据占用优化(mysql存储查询)
  • [4.9福建四校联考]
  • [Angularjs]asp.net mvc+angularjs+web api单页应用之CRUD操作
  • [Bada开发]初步入口函数介绍
  • [BUG] Hadoop-3.3.4集群yarn管理页面子队列不显示任务
  • [BUUCTF NewStarCTF 2023 公开赛道] week4 crypto/pwn
  • [CentOs7]iptables防火墙安装与设置
  • [CLR via C#]11. 事件