洛谷 P9007 [入门赛 #9] 最澄澈的空与海 (Hard Version)

这道题可不入门。

[Problem Discription] \color{blue}{\texttt{[Problem Discription]}} [Problem Discription]

给定 n n n,求有多少组 ( x , y , z ) (x,y,z) (x,y,z) 满足:

  1. x − y z = n ! x-\dfrac{y}{z}=n! xzy=n!
  2. x − y z = n ! n \dfrac{x-y}{z}=\dfrac{n!}{n} zxy=nn!

其中 n ! n! n! 表示 n n n 的阶乘,即 ∏ i = 1 n i \prod\limits_{i=1}^{n} i i=1ni x , y , z x,y,z x,y,z 为整数,可以是负整数。

多组询问。 1 ≤ T ≤ 1 × 1 0 5 , 1 ≤ n ≤ 1 × 1 0 6 1 \leq T \leq 1 \times 10^{5},1 \leq n \leq 1 \times 10^{6} 1T1×105,1n1×106

[Analysis] \color{blue}{\texttt{[Analysis]}} [Analysis]

作为一个经历了高考摧残的人,最会干的事情就是化简冗长的式子。

干瞪眼看不出这两个式子有什么规律,变量太多了,因此考虑先消元。

x − y z = n ! x-\dfrac{y}{z}=n! xzy=n! x = y z + n ! x=\dfrac{y}{z}+n! x=zy+n!,把它带入第二个式子中可得:

x − y z = y z + n ! − y z = y + z n ! − z y z 2 = n ! n \begin{aligned} \dfrac{x-y}{z}&=\dfrac{\dfrac{y}{z}+n!-y}{z}\\ &=\dfrac{y+zn!-zy}{z^2}\\ &=\dfrac{n!}{n} \end{aligned} zxy=zzy+n!y=z2y+zn!zy=nn!

通分,

n y − n z n ! − n z y = n ! z 2 n ( z − 1 ) y = n ! z ( n − z ) y = ( n − 1 ) ! z ( n − z ) z − 1 \begin{aligned} ny-nzn!-nzy&=n!z^2\\ n(z-1)y&=n!z(n-z)\\ y&=\dfrac{(n-1)!z(n-z)}{z-1} \end{aligned} nynzn!nzyn(z1)yy=n!z2=n!z(nz)=z1(n1)!z(nz)

因此,满足题意的 ( z − 1 ) (z-1) (z1) 一定是 ( n − 1 ) ! z ( n − z ) (n-1)!z(n-z) (n1)!z(nz) 的因数。除了 z = 2 z=2 z=2 外, ( z − 1 ) (z-1) (z1) 不会是 z z z 的因数,且 gcd ⁡ ( z − 1 , z ) = 1 \gcd(z-1,z)=1 gcd(z1,z)=1,因此 ( z − 1 ) (z-1) (z1) ( n − 1 ) ! ( n − z ) (n-1)!(n-z) (n1)!(nz) 的因数。然而这个式子上下都含有 z z z,愚蠢的人脑是分析不出什么东西来的。

考虑引入新的参数 k k k

( n − 1 ) ! ( n − z ) = k ( z − 1 ) n ! − ( n − 1 ) ! z = k z − k [ ( n − 1 ) ! + k ] z = n ! + k z = n ! + k ( n − 1 ) ! + k \begin{aligned} (n-1)!(n-z)&=k(z-1)\\ n!-(n-1)!z&=kz-k\\ \left [ (n-1)!+k\right ]z&=n!+k\\ z&=\dfrac{n!+k}{(n-1)!+k} \end{aligned} (n1)!(nz)n!(n1)!z[(n1)!+k]zz=k(z1)=kzk=n!+k=(n1)!+kn!+k

实话实说,这是一个非常美的式子,可惜它和上面一样,上下都含有 k k k,因此从难度上并没有变化。

思路貌似到这里就断了,怎么办?当然是看题解去(bushi)。

上面是把消去了 x x x 保留 y y y,行不通的时候当然试试消去 y y y 留下 x x x 啦。

也不用重新计算,只需要把 y y y z z z 表达的那个式子带入 x x x 中,就可以得到:

x = y z + n ! = ( n − 1 ) ( n − 1 ) ! z z − 1 x=\dfrac{y}{z}+n!=\dfrac{(n-1)(n-1)!z}{z-1} x=zy+n!=z1(n1)(n1)!z

同样, z ≠ 2 z \not = 2 z=2 时, ( z − 1 ) (z-1) (z1) 不是 z z z 的因数,因此 ( z − 1 ) (z-1) (z1) 一定是 ( n − 1 ) ( n − 1 ) ! (n-1)(n-1)! (n1)(n1)! 的因数。 z = 2 z=2 z=2 时, z − 1 = 1 z-1=1 z1=1 当然也是 ( n − 1 ) ( n − 1 ) ! (n-1)(n-1)! (n1)(n1)! 的因数。

因此问题转化为求 ( n − 1 ) ( n − 1 ) ! (n-1)(n-1)! (n1)(n1)! 的因数的个数。这个问题和原问题是等价的。记答案为 ans ( n ) \text{ans}(n) ans(n)

为什么?

考虑 ( n − 1 ) ( n − 1 ) ! (n-1)(n-1)! (n1)(n1)! 的一个因数 z z z,带入上式就一定可以唯一的算出一个 x ( z ) , y ( z ) x(z),y(z) x(z),y(z) x ( z ) x(z) x(z) 必然是一个整数。而 y = z ( x − n ! ) y=z(x-n!) y=z(xn!)(由最开始的式子变形而来)在 x , z x,z x,z 都是整数的情况下当然是整数。因此一个 z z z 就唯一确定一组 ( x , y , z ) (x,y,z) (x,y,z),而不同的 z z z 确定的当然是不同的 ( x , y , z ) (x,y,z) (x,y,z)。两个问题的解构成一一映射。

根据因数个数定理,我们需要求的就是 ( n − 1 ) ( n − 1 ) ! (n-1)(n-1)! (n1)(n1)! 不同质因数出现的次数。

设每个质因数出现的次数为 f ( p i ) f(p_{i}) f(pi)。答案即为 ∏ i = 1 prime count ( 1 + f ( p i ) ) \prod\limits_{i=1}^\text{prime count}\left (1+f(p_{i}) \right ) i=1prime count(1+f(pi))

不能每次都重新求,考虑怎么从 ans ( n − 1 ) \text{ans}(n-1) ans(n1) 递推得到 ans ( n ) \text{ans}(n) ans(n)

我们可以快速的将 n n n ( n − 1 ) (n-1) (n1) 分解质因数,然后 f ( p i ) f(p_{i}) f(pi) 减去 ( n − 1 ) (n-1) (n1) 的质因数出现次数,加上两倍的 n n n 的质因数个数就行了(因为阶乘和阶乘前各有一个 n n n,所以是两倍)。

但是根号级别的分解质因数还是太慢了,能不能降低时间复杂度呢?

答案是可以的。如果我们知道 n n n 的质因数都有谁,就不用一个一个数去实验了。当然不能把所有质因数都记下来(都记下来了还要试除法干嘛了),但是通过线性筛,我们可以顺便得到每个数的最小质因数是多少。每次除以最小质因数就可以大大加快算法了。

配合线性求逆元,程序跑得飞快。

还漏了一个问题,在上面那个式子中, ( z − 1 ) (z-1) (z1) 是作为分母的,因此 z ≠ 1 z \not = 1 z=1。有没有 z = 1 z=1 z=1 的情况呢?

z = 1 z=1 z=1 时有 x − y = n ! = n ! n x-y=n!=\dfrac{n!}{n} xy=n!=nn!,因此 n = 1 n=1 n=1。因此只有 n = 1 n=1 n=1 时答案为无穷。

Code \color{blue}{\text{Code}} Code

int f[N],n,T,ans[N];int prime[N],prcnt;
bool is_prime[N];
int minn_prime[N];
void get_prime(int n){for(int i=2;i<=n;i++)is_prime[i]=true;for(int i=2;i<=n;i++){if (is_prime[i]){minn_prime[i]=i;prime[++prcnt]=i;}for(int j=1;j<=prcnt;j++){if (1ll*i*prime[j]>n) break;is_prime[i*prime[j]]=false;minn_prime[i*prime[j]]=prime[j];if (i%prime[j]==0) break;}}
}int ksm(int a,int b){自己写快速幂
}int inv[N],fac[N];void init_inv(int n){fac[0]=1;for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;int tmp=ksm(fac[n],mod-2);inv[n]=1ll*fac[n-1]*tmp%mod;for(int i=n-1;i>=1;i--){tmp=1ll*tmp*(i+1)%mod;inv[i]=1ll*tmp*fac[i-1]%mod;}
}vector<pair<int,int> > prdiv;
void dp_init(int n){int cur=1;ans[0]=1;for(int i=1;i<=n;i++){prdiv.clear();int tmp=i;while (tmp!=1){int cnt=0,div=minn_prime[tmp];while (tmp%div==0){tmp/=div;cnt++;}prdiv.push_back(make_pair(div,cnt));}tmp=prdiv.size();for(int j=0;j<tmp;j++){int val=prdiv[j].first,cnt=prdiv[j].second;cur=1ll*cur*inv[1+f[val]]%mod;f[val]+=(cnt<<1);cur=1ll*cur*(1+f[val])%mod;}ans[i]=cur;for(int j=0;j<tmp;j++){int val=prdiv[j].first,cnt=prdiv[j].second;cur=1ll*cur*inv[1+f[val]]%mod;f[val]-=cnt;cur=1ll*cur*(1+f[val])%mod;}}
}int main(){get_prime(1e6);init_inv(1e6);dp_init(1e6);T=read();for(int Case=1;Case<=T;Case++){n=read();if (n==1) printf("inf\n");else printf("%d\n",ans[n-1]);}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/79746.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PostgreSQL 的 pg_stat_file 函数

PostgreSQL 的 pg_stat_file 函数 pg_stat_file 是 PostgreSQL 提供的一个系统管理函数&#xff0c;用于获取文件系统上文件的元数据信息。这个函数对于数据库管理员进行文件级别的监控和诊断非常有用。 一 函数基本语法 pg_stat_file(filename text [, missing_ok boolean …

关于麒麟服务器实现docker-compose服务开机自启

我本地服务器环境是麒麟V10版本&#xff1a; 首先确定docker-compose服务绝对路径命令&#xff1a; which docker-compose我这里输出是&#xff1a;/usr/bin/docker-compose 编辑服务文件&#xff1a; sudo vim /etc/systemd/system/docker-compose-webup.service[Unit] Desc…

基于 jQuery 实现复选框全选与选中项查询功能

在 Web 开发中&#xff0c;复选框是常见的交互元素&#xff0c;尤其是在涉及批量操作、数据筛选等场景时&#xff0c;全选功能和选中项查询功能显得尤为重要。本文将介绍如何使用 HTML、CSS 和 jQuery 实现一个具备全选、反选以及选中项查询功能的复选框组&#xff0c;帮助开发…

AfuseKt2.4.2 | 支持阿里云盘、Alist等平台视频播放,具备自动海报墙刮削功能的强大播放器

AfuseKt是一款功能强大的安卓端在线视频播放器&#xff0c;支持播放阿里云盘、Alist、WebDAV等平台的视频内容。它具备自动海报墙刮削功能&#xff0c;能自动生成影片信息和海报墙&#xff0c;提供良好的视觉体验。此外&#xff0c;它还支持倍速播放、字幕、音轨切换等多种实用…

Netlink在SONiC中的应用

Netlink在SONiC中的应用 Netlink介绍 Netlink 是 Linux 内核态程序与用户空间程序之间进行通信的机制之一&#xff0c;原本是用于传递网络协议栈中的各种控制消息。它采用和套接字&#xff08;socket&#xff09;编程接口相同的形式&#xff0c;常用于配置内核网络子系统&…

语音合成之十一 提升TTS语音合成效果:低质量数据清洗、增强与数据扩增

低质量数据清洗、增强与数据扩增 1. 引言&#xff1a;TTS的基石——数据质量2. 基础&#xff1a;TTS数据准备工作流2.1 规划&#xff1a;定义蓝图2.2 执行&#xff1a;从原始数据到训练就绪格式2.3 最佳实践与可复现性 3. 攻克缺陷&#xff1a;低质量语音数据的清洗与增强3.2 手…

Java IO流分类与记忆方法

Java IO流分类与记忆方法 在Java IO流体系中,理解节点流和包装流的区别是掌握IO编程的关键。 一、核心分类标准 1. 节点流(Node Stream) 直接对接数据源:直接连接物理IO设备(文件、网络、内存等)基础功能:提供最基础的读写能力命名特征:通常包含数据源类型名称(如Fi…

架构师如何构建个人IP:职业规划与业务战略的双重提升

在数字化时代&#xff0c;软件架构师的角色已从单纯的技术专家转变为兼具技术领导力和业务影响力的复合型人才。如何构建个人IP&#xff0c;提升行业影响力&#xff0c;成为架构师职业发展的关键课题。本文从个人认知、业务战略、架构决策、产品思维四个维度&#xff0c;探讨架…

vscode运行python的快捷键

以下是一些在 VS Code 中运行 Python 代码的常用快捷键&#xff1a; 运行 Python 文件 Windows/Linux &#xff1a;Ctrl F5。此快捷键会直接运行当前打开的 Python 文件&#xff0c;不会自动进入调试模式。若之前有配置过终端&#xff0c;一般会使用配置好的终端来运行&…

使用OpenCV 和 Dlib 实现疲劳检测

文章目录 引言1.相关技术介绍2. 系统原理2.1 眼睛纵横比(EAR)算法2.2 系统工作流程 3.代码解析3.1 关键函数说明3.2 主循环逻辑 4.实际应用效果5.参数调优建议6.总结 引言 疲劳驾驶是交通事故的主要原因之一。本文将介绍如何使用Python和计算机视觉技术构建一个实时疲劳驾驶检…

VBA实现后入先出(LIFO)库存统计

先入先出&#xff08;FIFO&#xff09;比较容易理解&#xff0c;买入早的优先卖出。与之对应的是后人先出&#xff08;LIFO&#xff09;&#xff0c;就是优先卖出最近买入的&#xff0c;例如&#xff1a;第8行卖出2K&#xff0c;当天还没有买入记录&#xff0c;只能找前一天的买…

Python中的客户端和服务端交互的基本内容

目录 网络协议 网络的通信方式 需要安装的组件和需要导入的包模块 安装的组件 导入包模块 如何创建客户端 如何创建服务端 网络协议 IPV4&#xff1a;是互联网协议的第四版&#xff0c;也是目前广泛使用的网络协议。它使用32位地址格式&#xff0c;理论上可以提供约43亿…

【硬核攻坚】告别CUDA OOM!DeepSeek部署显存瓶颈终极解决方案:三大策略高效落地

目录 引言:大模型落地的“甜蜜”与“烦恼”DeepSeek剖析:为何它如此“吃”显存?CUDA OOM的“幽灵”:现象、根因与诊断破局之道:三大策略驯服显存“猛兽” 策略一:模型量化 - 给模型“瘦身”的艺术策略二:动态优化 - 榨干硬件潜能策略三:分布式扩展 - 集群的力量实战演练…

JavaSE核心知识点01基础语法01-01(关键字、标识符、变量)

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 JavaSE核心知识点01基础语法01-01&#xff0…

【最新Python包管理工具UV的介绍和安装】

介绍 uv是一个非常快的 Python 包安装程序和 pip 解析器&#xff0c;用 Rust 编写&#xff0c;设计为pip-tools的直接替代品。 以下是官网给出的UV与其他包管理工具解决依赖&#xff08;左&#xff09;和安装包&#xff08;右&#xff09;的对比图。 可以看出UV是一个极快的 P…

麒麟、UOS系统在线打开word文件并提取修订痕迹

麒麟、UOS系统在线打开word文件并提取修订痕迹 查看本示例演示效果&#xff08;Windows版&#xff09; 查看本示例演示效果&#xff08;国产版&#xff09;本示例关键代码的编写位置&#xff0c;请参考“开始 - 快速上手”里您所使用的开发语言框架的最简集成代码 注意 本文中…

【SpringAI+阿里云百炼】AI对话4个Demo

基于SpringAI和阿里云百炼平台&#xff0c;实现了四个AI对话的小Demo 小团团对话机器人哄哄模拟器培训班智能客服仿ChatPDF 笔记如下:语雀知识笔记《SpringAI》

【数据结构】单链表的增删查改

本文是小编巩固自身而作&#xff0c;如有错误&#xff0c;欢迎指出&#xff01; 1.链表的概念 概念&#xff1a;链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的 指针链接次序实现的。 和之前的顺序表不同&#xff0c;顺序一般…

LeetCode 1128.等价多米诺骨牌对的数量:计数

【LetMeFly】1128.等价多米诺骨牌对的数量&#xff1a;计数 力扣题目链接&#xff1a;https://leetcode.cn/problems/number-of-equivalent-domino-pairs/ 给你一组多米诺骨牌 dominoes 。 形式上&#xff0c;dominoes[i] [a, b] 与 dominoes[j] [c, d] 等价 当且仅当 (a …

以太坊智能合约开发框架:Hardhat v2 核心功能从入门到基础教程

一、设置项目 Hardhat 项目是安装了 hardhat 包并包含 hardhat.config.js 文件的 Node.js 项目。 操作步骤&#xff1a; ①初始化 npm npm init -y②安装 Hardhat npm install --save-dev hardhat③创建 Hardhat 项目 npx hardhat init如果选择 Create an empty hardhat.…