【题解】线性筛素数 线性统计范围质因数 小Y的智力游戏
来源:互联网 发布:农村淘宝怎么开店 编辑:程序博客网 时间:2024/05/26 02:18
对于思维有一定锻炼
关于“线性统计范围质因数”是指统计1到n范围每个数的质因数的总幂次(也可以理解为统计n!的每个质因数的幂次)
例:n = 10时
分解质因数分别有
那么结果应为
表示2的总幂次是8,3的总幂次是3,5的总幂次为2,7的总幂次为1
题目
题目描述
小 Y 最近迷上了一款智力游戏。(当然小 Y 还是很好学的)
这款智力游戏就是让你从 1 到 N 这 N 个数中,选取若干个不相等的正整数,使得它们的乘积为一个
完全平方数,同时,这个乘积也将成为你的得分。
他(或她,以后这个括号就省略了)想知道最大得分对 1000000007 的模值。
输入
输入文件名 game.in
一行一个正整数 N,代表数字的个数。
输出
输出文件名 game.out
一行一个正整数,代表最大得分对 1000000007 的模值。
输入输出样例
输入输出样例】
数据范围
对于 30%的数据,保证有 n≤50。
对于 60%的数据,保证有 n≤1000。
对于 70%的数据,保证有 n≤10000。
对于 80%的数据,保证有 n≤100000。
对于 90%的数据,保证有 n≤1000000。
对于 100%的数据,保证有 n≤3000000。
题解
可以想到,将结果质因数分解后每个质因数的幂次一定是偶数才能是完全平方数
那么就转换为求出答案的每个质因数幂次最多可以是多少
为保证一定是由1到n中不相等的数乘来,直接从n!的质因数入手即可
根据数据范围现在就是要寻求快速统计n!质因数幂次的方法
有两种方法,按时空复杂度优秀度升序分别阐述
方法一
首先要统计质因数幂次肯定怎样都要先把质数求出来,只谈复杂度Onlogn和On的求法都可以,但是可以利用On的线性求法使统计幂次更快求出
在线性筛中,是通过保证每个数都只被最小的质因数计算一遍来实现线性复杂度,现在我们要统计幂次,也可以在线性筛时一起保存每个数的最小质因数,这样在统计时就可以将n不断缩小。具体来说:每次除以当前最小质因数,并将此质因数幂次统计加1
每次至少除以2,复杂度为nlogn
(将求解问题转化为另一个同样的范围更小的问题)
方法二
虽然方法一对于本问题已经完全足够,但是还能更优!
由txc同学本次考试独立发现(ysp也是同样的方法)
感谢txc的解释
方法一需要开大小为n的int数组在线性筛时来存,方法二可根据n直接求出
txc是以质因数含2为例将2, 4, 6, 8…列出,求出每个数含2的幂次,观察可发现规律
不过我观察代码,觉得还可以有这种解释
对于每个质因数,可每一次都对每个数都试除,每次加上有此质因数的个数,直至不能再除即可
当然具体操作不是直接这么操作,其实每次拿n除以当前质因数向下取整所得就是由此质因数的个数。为方便操作,不让n变,逆向,拿n除以当前质数i的次幂,直至当前质数i次幂大于n为止
以n = 18,当前质数p = 2为例
2, 4, 6, 8, 10…含二幂次为
1, 2, 1, 3, 1, 2, 1, 4, 1
i = 1时
0, 1, 0, 2, 0, 1, 0, 3, 0
i = 2时
0, 0, 0, 1, 0, 0, 0, 2, 0
…
每次变化的个数就是
n除以当前质因数向下取整所得
大概算时间复杂度也是nlogn,但测试速度小于方法一
空间复杂度也更小
代码
#include <cstdio>typedef long long ll;const int maxr = 216820, maxn = 3e6 + 100, mod = 1000000007;bool np[maxn];int pri[maxr], tot = 0, cnt[maxn];ll QPow(ll x, int n){ n -= n & 1; ll res = 1; while (n){ if (n & 1) res = res * x % mod; x = x * x % mod; n >>= 1; }return res;}int main (){ int n; scanf ("%d", &n); for (int i = 2; i <= n; ++i){ if (!np[i])pri[++tot] = i; for (int j = 1, t = pri[1] * i; j <= tot && t <= n; t = pri[++j] * i){ np[t] = 1; if (i % pri[j] == 0) break; } } ll sum; for (int i = 1; i <= tot; ++i){ sum = 1; while (sum <= n){ sum *= pri[i]; cnt[i] += n / sum; } } ll ans = 1; for (int i = 1; i <= tot; ++i) ans = ans * QPow(pri[i], cnt[i]) % mod; printf ("%lld", ans); return 0;}
- 【题解】线性筛素数 线性统计范围质因数 小Y的智力游戏
- 小Y的智力游戏
- 1025: [SCOI2009]游戏 线性筛素数+DP
- 线性筛素数的方法
- 线性筛素数的欧拉筛法
- [线性筛 质因数分解] 51Nod 1643 小Q的家庭作业
- 一个线性时间复杂度的质因数分解函数(查找全部的素数、得到全部的质因数分解个数)
- 素数的线性筛选
- 线性筛素数
- 线性时间筛素数
- 线性素数筛
- 线性时间素数筛
- 线性筛素数模板
- 线性素数筛法
- [线性筛]素数个数
- 线性筛求素数
- 线性筛素数
- 线性筛素数法
- 跨域问题和处理跨域的方法
- linux目录操作
- poj 1269 Intersecting Lines 【直线相交】
- 数论前奏-整数和mod
- 马的移动问题(国际象棋)
- 【题解】线性筛素数 线性统计范围质因数 小Y的智力游戏
- TI的开发资源
- Android 网络编程(一)HTTP协议
- 20170722日常总结
- SpringMVC接收页面表单参数
- stat查看文件属性
- 学生过程知识点
- Python学习之argparse模块
- Bigdata Development Java_Study_01(二进制计算符号,Math常用方法)