bjfu1211 推公式,筛素数
题目是求fun(n)的值
fun(n)= Gcd(3)+Gcd(4)+…+Gcd(i)+…+Gcd(n).
Gcd(n)=gcd(C[n][1],C[n][2],……,C[n][n-1])
C[n][k] means the number of way to choose k things from n things.
n最大一百万,马上反映到可能是递推打表。
首先肯定是推公式了,fun(n)其实就是Gcd(n)的一个前n项和,没意义,直接看Gcd(n),把前几项列出来,发现公式是Gcd(n) = lcm(1,……,n-1,n)/lcm(1,……,n-1),其中lcm是求若干个数的最小公倍数。例如Gcd(1)=lcm(1)=1, Gcd(2)=lcm(1,2)/lcm(1)=2,
Gcd(6)=lcm(1,2,3,4,5,6)/lcm(1,2,3,4,5)=60/60=1
于是我马上想到了方法,先筛法打出一百万以内的素数表,然后从lcm(1,2)开始逐个往后递推lcm(1,……,n-1,n),开一个数组来表示其值(数组每一位表示某个素数,值表示这个素因子的个数)。但是这样的话,递推的时候必须遍历素数表,就算只考虑1000以内的素数,也超过100个,很有可能超时。
不过因为是学弟出的题,本着测试的态度,我按这个思路打了一个,果然超时,看来数据不算太水。
/*
* Author : ben
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <functional>
#include <numeric>
#include <cctype>
using namespace std; #ifdef ON_LOCAL_DEBUG
#else
#endif
typedef long long LL;
const int MAXN = ;
LL ans[MAXN];
int pn, pt[MAXN], num[MAXN];
bool ip[MAXN];
int N = ;
void init_prime_table() {
memset(ip, true, sizeof(ip));
int i;
ip[] = false;
pn = ;
pt[pn++] = ;
for (i = ; i < N; i += ) {
ip[i] = false;
}
for (i = ; i * i <= N; i += ) {
if (!ip[i])
continue;
pt[pn++] = i;
for (int s = * i, j = i * i; j < N; j += s)
ip[j] = false;
}
for (; i < N; i++) {
if (ip[i]) {
pt[pn++] = i;
}
}
}
inline int mypow(int a, int b) {
int ret = ;
while (b--) {
ret *= a;
}
return ret;
} int comput() {
ans[] = ;
for (int i = ; i <= N; i++) {
if (ip[i]) {
num[i]++;
ans[i] = i;
continue;
}
int _gcd = ;
int n = i;
for (int j = ; j < pn; j++) {
if (n == ) {
break;
}
if (n > && ip[n]) {
break;
}
int t = ;
while (n % pt[j] == ) {
t++;
n = n / pt[j];
}
if (t > num[pt[j]]) {
_gcd *= mypow(pt[j], t - num[pt[j]]);
num[pt[j]] = t;
}
}
ans[i] = _gcd;
}
for (int i = ; i < MAXN; i++) {
ans[i] += ans[i - ];
}
return ;
} int main() {
#ifdef ON_LOCAL_DEBUG
freopen("data.in", "r", stdin);
#endif
int n;
// get_prime_table(MAXN);
init_prime_table();
// pn = pt.size();
memset(num, , sizeof(num));
comput();
while (scanf("%d", &n) == ) {
printf("%I64d\n", ans[n]);
}
return ;
}
下面是正解。正解的方法对上面那种方法的改进类似于筛法对普通求素数法的改进。原来的方法这么工作:比如在递推到n=8的时候,发现8有三个素因子2,而之前的lcm里只有两个素因子2,所以这次的值会再乘一个2。那么新方法直接倒过来,当递推到2的时候,发现2是素数,那么就把2^2,2^3,2^4等等的ans里都预先乘上一个2。这样就避免了遍历素数表,降低了复杂度,而且代码更为简洁。代码如下:
/*
* Author : ben
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <functional>
#include <numeric>
#include <cctype>
using namespace std; #ifdef ON_LOCAL_DEBUG
#else
#endif
typedef long long LL;
const int MAXN = ;
LL ans[MAXN];
int pn, pt[MAXN];
bool ip[MAXN];
int N = MAXN;
void init_prime_table() {
memset(ip, true, sizeof(ip));
int i;
ip[] = false;
pn = ;
pt[pn++] = ;
for (i = ; i < N; i += ) {
ip[i] = false;
}
for (i = ; i * i <= N; i += ) {
if (!ip[i])
continue;
pt[pn++] = i;
for (int s = * i, j = i * i; j < N; j += s)
ip[j] = false;
}
for (; i < N; i++) {
if (ip[i]) {
pt[pn++] = i;
}
}
} int comput() {
fill(ans, ans + N + , );
for (int i = ; i <= N; i++) {
if (ip[i]) {
LL t = i;
while (t <= N) {
ans[t] *= i;
t *= i;
}
}
}
for (int i = ; i < MAXN; i++) {
ans[i] += ans[i - ];
}
return ;
} int main() {
#ifdef ON_LOCAL_DEBUG
// freopen("test.in", "r", stdin);
// freopen("data.out", "w", stdout);
freopen("data.in", "r", stdin);
#endif
int n;
init_prime_table();
comput();
while (scanf("%d", &n) == ) {
printf("%I64d\n", ans[n]);
}
return ;
}
bjfu1211 推公式,筛素数的更多相关文章
- 【板子】gcd、exgcd、乘法逆元、快速幂、快速乘、筛素数、快速求逆元、组合数
1.gcd int gcd(int a,int b){ return b?gcd(b,a%b):a; } 2.扩展gcd )extend great common divisor ll exgcd(l ...
- ACM-ICPC 2018 南京赛区网络预赛 J题Sum(线性筛素数)
题目链接:https://nanti.jisuanke.com/t/30999 参考自博客:https://kuangbin.github.io/2018/09/01/2018-ACM-ICPC-Na ...
- codeforces 185A Plant(推公式)
Plant [题目链接]Plant [题目类型]推公式 &题解: 这个是可以推公式的: 每年的总个数是4^n个,设n年时向上的个数是x个,向下的个数是y个,那么n+1年时,向上的个数是3* x ...
- 欧拉函数O(sqrt(n))与欧拉线性筛素数O(n)总结
欧拉函数: 对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目. POJ 2407.Relatives-欧拉函数 代码O(sqrt(n)): ll euler(ll n){ ll ans=n; ...
- 全网一定不是最好懂的C++线性筛素数
Part 0:概念 先给几个概念(很重要): 合数:如果\(xy=z\text{且}x,y\text{为正整数}\),我们就说\(x,y\text{是}z\text{的合数}\) 素数:如果数\(a\ ...
- CF449C Jzzhu and Apples (筛素数 数论?
Codeforces Round #257 (Div. 1) C Codeforces Round #257 (Div. 1) E CF450E C. Jzzhu and Apples time li ...
- HDU 4873 ZCC Loves Intersection(JAVA、大数、推公式)
在一个D维空间,只有整点,点的每个维度的值是0~n-1 .现每秒生成D条线段,第i条线段与第i维度的轴平行.问D条线段的相交期望. 生成线段[a1,a2]的方法(假设该线段为第i条,即与第i维度的轴平 ...
- HDU 4870 Rating(概率、期望、推公式) && ZOJ 3415 Zhou Yu
其实zoj 3415不是应该叫Yu Zhou吗...碰到ZOJ 3415之后用了第二个参考网址的方法去求通项,然后这次碰到4870不会搞.参考了chanme的,然后重新把周瑜跟排名都反复推导(不是推倒 ...
- 洛谷P3383 【模板】线性筛素数
P3383 [模板]线性筛素数 256通过 579提交 题目提供者HansBug 标签 难度普及- 提交 讨论 题解 最新讨论 Too many or Too few lines 样例解释有问题 ...
随机推荐
- 适合我胃口的angular.js学习资料
断断续续弄了半年的ANGULAR.JS学习资料,网上下载了N多资料,测试了很多次. 现在只能算是入门,因时间问题,现在要转入其它领域. 如果以后要拾起来,下面这个PDF比较对我胃口. <Angu ...
- hdu 1755 A Number Puzzle
这题枚举k节省时间 ;}
- emms指令在MMX指令中的作用
emms指令在MMX指令中的作用 转自:http://blog.csdn.net/psusong/archive/2009/01/08/3737047.aspx MMX和SSE都是INTEL开发的基于 ...
- spring autoWire注解和@resource注解区别
1.autoWire注解主要是按类型匹配.因为autowire的扫描机制,是按照接口类型来扫描bean的. 而JSR250 @resource注解是通过名称扫描注入的. @autowire注解的扫描方 ...
- HTML5 文件API(二)
1.FileSystem概述及浏览器检 2.申请磁盘配额 3.创建文件
- 猜拳 GuessFist
import java.util.Scanner;import java.util.Random;/***跟电脑玩石头剪刀布,需要从控制台输入信息,*然后去判断,然后给予反馈信息*/public cl ...
- 代码自动生成工具_java版
项目结构: 这里要实现的功能是,当我们给出了bean,如:Admin,User,People等实体类后, 我想用代码自动生成我想要的代码,最后生成的效果: 也就是说为每一个bean都生成相应的Dao, ...
- HDU-4661 Message Passing 树形DP,排列组合
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4661 题意:有n个人呈树状结构,每个人知道一个独特的消息.每次可以让一个人将他所知的所有消息告诉和他相 ...
- px,dp,sp单位转换工具类
在layout中使用dp 在代码中getWidth系列得到的是px 设置字体大小时使用的是sp /** * Android大小单位转换工具类 */ public class PxDpSpUtil { ...
- POJ 3185 The Water Bowls(高斯消元-枚举变元个数)
题目链接:http://poj.org/problem?id=3185 题意:20盏灯排成一排.操作第i盏灯的时候,i-1和i+1盏灯的状态均会改变.给定初始状态,问最少操作多少盏灯使得所有灯的状态最 ...