樱花(信息学奥赛一本通 1624)

【题目描述】

原题来自:HackerRank Equations

求不定方程: 1/x + 1/y = 1/n!

的正整数解 (x,y)的数目。

【输入】

一个整数 n。

【输出】

一个整数,表示有多少对 (x,y) 满足题意。答案对 109+7 取模。

【输入样例】

2

【输出样例】

3

【提示】

样例说明

共有三个数对 (x,y) 满足条件,分别是 (3,6),(4,4) 和 (6,3)。

数据范围与提示:

对于 30% 的数据,n≤100;

对于全部数据,1≤n≤106 。


(这里不得不吐糟一下,书上把题目打错了啦,n!写成了n,害得我还以为这道题可以暴力去做,结果光荣的爆零了(▼⊿▼))

首先呢就是用数学方法把这个不定方程变化一下,令y=n+a(x、y肯定比n大啦,可以自己推导一下),很容易就得到了 x = (n!*n!) / a+ n!

那么因为n!为整数、x也为整数,所以(n!*n!) / a一定也为整数。那要求x的个数的话就是要求满足(n!*n!) / a为整数的a的个数啦

所以说这道题很快就转化成了一道求约数个数的题目。

然后就是唯一分解定理和约数个数定理...

上代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e6+1,M=1e9+7;
 4 int a[N],n,v[N],cnt,b[N],num[N];//b[x]表示x的最小质因子是质数中的第几号
 5 long long ans=1;
 6 int read()
 7 {
 8     int x=0,f=1;
 9     char ch=getchar();
10     while(ch<‘0‘||ch>‘9‘)
11     {
12         if(ch==‘-‘) f=-1;
13         ch=getchar();
14     }
15     while(ch>=‘0‘&&ch<=‘9‘)
16     {
17         x=x*10+ch-‘0‘;
18         ch=getchar();
19     }
20     return x*f;
21 }
22 void write(int x)
23 {
24     if(x<0)
25     {
26         putchar(‘-‘);
27         x=-x;
28     }
29     if(x>9) write(x/10);
30     putchar(x%10+‘0‘);
31 }
32 void pre()
33 {
34     for(int i=2;i<=1000000;i++)
35     {
36         if(!v[i])a[++cnt]=i,b[i]=cnt;
37         for(int j=1;j<=cnt&&a[j]*i<=1000000;j++)
38         {
39             v[i*a[j]]=1;b[i*a[j]]=j;
40             if(i%a[j]==0)break;
41         }
42     }
43 }
44 void ff(int x)
45 {
46     while(x!=1)
47     {
48         num[b[x]]++;//num[i]表示i这个序号代表的质因子出现的次数(也就是b[i]的幂的次数啦)
49         x/=a[b[x]];//x不断更新
50     }
51 }
52 int main()
53 {
54
55     n=read();
56     pre();
57     for(int i=2;i<=n;i++)
58         ff(i);
59     for(int i=1;i<=cnt;i++)
60         ans=ans*(num[i]*2+1)%M;
61     printf("%lld",ans);
62     return 0;
63 }

//参考:这位大佬讲的hin好,点击%大佬的博客

原文地址:https://www.cnblogs.com/ljy-endl/p/11378174.html

时间: 2024-08-30 04:03:08

樱花(信息学奥赛一本通 1624)的相关文章

信息学奥赛一本通 5.4 状态压缩动态规划

#loj 10170. 「一本通 5.4 例 1」骑士 看数据范围n<=10,所以不是搜索就是状压dp,又因为搜索会超时所以用dp dp[i][k][j]表示现已经放到第i行,前面共有k个,这一行状态为j so,dp[i][k][j]=dp[i-1][k-num[j]][t] #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cma

【信息学奥赛一本通】第三部分_栈 ex1_4cale (中缀转后缀7符号)

其实这个中缀转后缀是费了很大功夫的,明白算法后第一次实现花了近三小时ORZ #include <stdio.h> #include <string.h> #include <ctype.h> char Mstr[511],Msta[511] = {'@'},Bstr[511]; int sta[511]; const short list[4][4] = {{0,-1,1,1},{1,0,1,1},{1,1,1,-2},{-1,-1,2,1}}; int level (

【信息学奥赛一本通】第三部分_队列 ex2_3produce 产生数

给出一个整数n(n<=2000)(代码可适用n<=10^31)和k个变换规则(k<=15). 规则:1.1个数字可以变换成另1个数字: 2.规则中右边的数字不能为零. BFS 1 #include <stdio.h> 2 #include <string.h> 3 #define maxn 1000 4 5 char num[33]; 6 int len,q[maxn],Visited[11]; 7 long long ans = 1; 8 9 int main

信息学奥赛一本通 5.1 区间类动态规划

石子合并[loj 10147] /* dp[i][j]=max or min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]) i<=k<j */ #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; inline int re

信息学奥赛一本通 5.2 树形动态规划

题解在代码中 二叉苹果树[loj 10153] /* 若要留q条边便是要留q+1个点 所以记忆化搜索 dp[pos][ans]=max(dp[pos][ans],dp[l[pos]][k]+dp[r[pos]][ans-k-1]+a[pos]) 0<=k<=ans-1 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<c

信息学奥赛一本通 提高篇 序列第k个数 及 快速幂

我是传送门 这个题首先是先判断是等差还是等比数列 等差的话非常简单: 前后两个数是等差的,举个栗子: 3 6 9 12 这几个数,(我感觉 1 2 3 4并说明不了什么) 每次都加3嘛,很容易看出,第一个数是3 * 1,第二个是3 * 2....以此类推 第k个数 = (第2个数 - 第1个数) * k ; (z - y) * k % 200907 % 200907 的原因是题目要求 但是这样并不能过 hack一下 4 7 10 13 用原先的公式:(7 - 4) * 4 % 200907 =

【信息学奥赛一本通 提高组】第二章 二分与三分

一.二分 二分法,在一个单调有序的集合或函数中查找一个解,每次分为左右两部分,判断解在那个部分并调整上下界,直到找到目标元素,每次二分都将舍弃一般的查找空间,因此效率很高. 二分常见模型 1.二分答案 最小值最大(或是最大值最小)问题,这类双最值问题常常选用二分法求解,也就是确定答案后,配合贪心,DP等其他算法检验这个答案是否合理,将最优化问题转化为判定性问题.例如,将长度为n的序列ai分为最多m个连续段,求所有分法中每段和的最大值的最小是多少? 2.二分查找 用具有单调性的布尔表达式求解分界点

求后序遍历(信息学奥赛一本通 1339)

假设有棵树,长下面这个样子,它的前序遍历,中序遍历,后续遍历都很容易知道. PreOrder: GDAFEMHZ InOrder: ADEFGHMZ PostOrder: AEFDHZMG 现在,假设仅仅知道前序和中序遍历,如何求后序遍历呢?比如,已知一棵树的前序遍历是"GDAFEMHZ",而中序遍历是"ADEFGHMZ"应该如何求后续遍历? 第一步,root最简单,前序遍历的第一节点G就是root. 第二步,继续观察前序遍历GDAFEMHZ,除了知道G是root,

最大子矩阵(信息学奥赛一本通 1224)

[题目描述] 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1×1)子矩阵. [输入] 输入是一个N×N的矩阵.输入的第一行给出N(0<N≤100).再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行).已知矩阵中整数的范围都在[−127,127]. [输出] 输出最大子矩阵的大小. [输入样例] 4 0 -2 -7 0 9 2 -6 2 -4 1