题目是求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 推公式,筛素数的更多相关文章

  1. 【板子】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 ...

  2. ACM-ICPC 2018 南京赛区网络预赛 J题Sum(线性筛素数)

    题目链接:https://nanti.jisuanke.com/t/30999 参考自博客:https://kuangbin.github.io/2018/09/01/2018-ACM-ICPC-Na ...

  3. codeforces 185A Plant(推公式)

    Plant [题目链接]Plant [题目类型]推公式 &题解: 这个是可以推公式的: 每年的总个数是4^n个,设n年时向上的个数是x个,向下的个数是y个,那么n+1年时,向上的个数是3* x ...

  4. 欧拉函数O(sqrt(n))与欧拉线性筛素数O(n)总结

    欧拉函数: 对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目. POJ 2407.Relatives-欧拉函数 代码O(sqrt(n)): ll euler(ll n){ ll ans=n; ...

  5. 全网一定不是最好懂的C++线性筛素数

    Part 0:概念 先给几个概念(很重要): 合数:如果\(xy=z\text{且}x,y\text{为正整数}\),我们就说\(x,y\text{是}z\text{的合数}\) 素数:如果数\(a\ ...

  6. CF449C Jzzhu and Apples (筛素数 数论?

    Codeforces Round #257 (Div. 1) C Codeforces Round #257 (Div. 1) E CF450E C. Jzzhu and Apples time li ...

  7. HDU 4873 ZCC Loves Intersection(JAVA、大数、推公式)

    在一个D维空间,只有整点,点的每个维度的值是0~n-1 .现每秒生成D条线段,第i条线段与第i维度的轴平行.问D条线段的相交期望. 生成线段[a1,a2]的方法(假设该线段为第i条,即与第i维度的轴平 ...

  8. HDU 4870 Rating(概率、期望、推公式) && ZOJ 3415 Zhou Yu

    其实zoj 3415不是应该叫Yu Zhou吗...碰到ZOJ 3415之后用了第二个参考网址的方法去求通项,然后这次碰到4870不会搞.参考了chanme的,然后重新把周瑜跟排名都反复推导(不是推倒 ...

  9. 洛谷P3383 【模板】线性筛素数

    P3383 [模板]线性筛素数 256通过 579提交 题目提供者HansBug 标签 难度普及- 提交  讨论  题解 最新讨论 Too many or Too few lines 样例解释有问题 ...

随机推荐

  1. Ubuntu环境下Nutch1.2 二次开发(添加中文分词)

    前提nutch1.2已部署到eclipse中 详见:http://www.cnblogs.com/cy163/archive/2013/02/19/2916419.html 1 部署IKAnalyze ...

  2. lintcode :搜索旋转排序数组

    题目 搜索旋转排序数组 假设有一个排序的按未知的旋转轴旋转的数组(比如,0 1 2 4 5 6 7 可能成为4 5 6 7 0 1 2).给定一个目标值进行搜索,如果在数组中找到目标值返回数组中的索引 ...

  3. 【mongoDB中级篇②】索引与expain

    索引的操作 数据库百分之八十的工作基本上都是查询,而索引能帮我们更快的查询到想要的数据.但是其降低了数据的写入速度,所以要权衡常用的查询字段,不必在太多字段上建立索引. 在mongoDB中默认是用bt ...

  4. switch… case 语句的用法

    switch… case 语句的用法   public class Test7 { public static void main(String[] args) { int i=5; switch(i ...

  5. C程序的内存分配

    一.预备知识-程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)- 由编译器自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. ...

  6. *CentOS下简单的MySQL数据库操作

    1.登录成功之后退出的话,直接输入quit或者exit即可.

  7. 神经网络指南Hacker's guide to Neural Networks

    Hi there, I'm a CS PhD student at Stanford. I've worked on Deep Learning for a few years as part of ...

  8. URAL 1957 Wrong Answer 暴力

    Wrong Answer 思路: 1.先枚举4的全排列,即球赛的所有可能结果,一共4!=24种情况 2.对于每种情况,DFS 未确定的比赛 的结果,判断这种情况是否可达. 剪枝: 1.对于每种全排列, ...

  9. 【原创】Kmeans算法 优缺点分析

    优点: 原理简单(靠近中心点),实现容易(1.2 天),聚类效果中上(依赖K的选择) 缺点: 1. 无法确定K的个数 (根据什么指标确定K) 2. 对离群点敏感 (容易导致中心点偏移) 3. 算法复杂 ...

  10. hibernate--关联映射(多对一,一对一)

    多对一 关联映射 --- many-to-one 场景:用户和组:从用户角度来,多个用户属于一个组(多对一 关联) 使用hibernate开发的思路:先建立对象模型(领域模型),把实体抽取出来. 目前 ...