码迷,mamicode.com
首页 > 其他好文 > 详细

【51nod】1227 平均最小公倍数

时间:2018-06-08 23:15:09      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:put   div   prim   source   efi   数论   TE   add   type   

题解

这个故事告诉们数论函数不要往分式上跑,你推不出来
好久没推式子了这么明显的转化我都忘了= =

首先\(A(n) = \frac{1}{n} \sum_{i = 1}^{n} \frac{i * n}{gcd(i,n)}\)
然后显然可以把n消掉
\(A(n) = \sum_{i = 1}^{n} \frac{i}{gcd(i,n)}\)
改为枚举约数
\(A(n) = \sum_{d = 1}^{n} \frac{1}{d}\sum_{i = 1}^{n} i [gcd(i,n) == d]\)
\(A(n) = \sum_{d | n} \sum_{i = 1}^{\frac{n}{d}} i [gcd(i,\frac{n}{d}) == 1]\)
有个欧拉函数的性质是,小于这个数的且与这个数互质的数的和是
\(\frac{n \phi(n) + [n = 1]}{2}\) 挺好理解的,因为一个与n互质的数p,n - p也和n互质
\(\frac{n \phi(n) + [n = 1]}{2} = \sum_{i = 1}^{n} i [gcd(i,n) == 1]\)
\(A(n) = \frac{1}{2} (\sum_{d | n} \frac{n}{d} \phi(\frac{n}{d}) + 1)\)

\(F(n) = \sum_{i = 1}^{n} A(i)\)
\(F(n) = \frac{1}{2} (\sum_{i = 1}^{n} \sum_{d | i} \frac{i}{d} \phi(\frac{i}{d}) + n)\)
\(F(n) = \frac{1}{2} (\sum_{i = 1}^{n} \sum_{d | i} d \phi(d) + n)\)
\(F(n) = \frac{1}{2} (\sum_{i = 1}^{n} \sum_{d = 1}^{\frac{n}{i}} d \phi(d) + n)\)

我们发现这个东西可以构造卷积啊
\(\sum_{d = 1}^{n} d \phi(d)\)
卷上一个\(Id(x) = x^{2}\)
那么我们就有
\(\sum_{i = 1}^{n} i^2 = \sum_{i = 1}^{n} \sum_{d | i}d \phi(d) \frac{i}{d}\)
\(\sum_{i = 1}^{n} i^2 = \sum_{k = 1}^{n} k \sum_{d = 1}^{\frac{n}{k}}d \phi(d)\)
那么就有
\(S(n) = \frac{n(n +1)(2n + 1)}{6} - \sum_{i = 2}^{n} i S(\lfloor \frac{n}{i} \rfloor)\)
然后用数论分块求\(F(n)\)即可

题解

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
//#define ivorysi
#define pb push_back
#define space putchar(‘ ‘)
#define enter putchar(‘\n‘)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define mo 974711
#define MAXN 1000000
#define RG register
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
        while(c < ‘0‘ || c > ‘9‘) {
            if(c == ‘-‘) f = -1;
            c = getchar();
        }
        while(c >= ‘0‘ && c <= ‘9‘) {
        res = res * 10 + c - ‘0‘;
        c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {putchar(‘-‘);x = -x;}
    if(x >= 10) {
        out(x / 10);
    }
    putchar(‘0‘ + x % 10);
}
int N;
const int MOD = 1000000007;
struct node {
    int x,v,next;
}E[100006];
int head[mo + 5],sumE,Inv2,Inv6;
int prime[MAXN + 5],tot,S[MAXN + 5],phi[MAXN + 5];
bool nonprime[MAXN + 5];
int inc(int a,int b) {
    a = a + b;
    if(a >= MOD) a -= MOD;
    return a;
}
int mul(int a,int b) {
    return 1LL * a * b % MOD;
}
void add(int u,int x,int v) {
    E[++sumE].x = x;E[sumE].v = v;E[sumE].next = head[u];
    head[u] = sumE;
}
void Insert(int x,int v) {
    add(x % mo,x,v);
}
int Query(int x) {
    int u = x % mo;
    for(int i = head[u] ; i ; i = E[i].next) {
        if(E[i].x == x) return E[i].v;
    }
    return -1;
}
int f(int x) {
    if(x <= MAXN) return S[x];
    int c = Query(x);
    if(c != -1) return c;
    int res = 0;
    for(int i = 2 ; i <= x ; ++i) {
        int r = x / (x / i);
        res = inc(res,1LL * (r - i + 1) * (r + i) / 2 % MOD * f(x / i) % MOD);
        i = r;
    }
    res = inc(1LL * x * (x + 1) % MOD * (2 * x + 1) % MOD * Inv6 % MOD,MOD - res);
    Insert(x,res);
    return res;
}
int calc(int x) {
    int res = 0;
    for(int i = 1 ; i <= x ; ++i) {
        int r = x / (x / i);
        res = inc(res,mul(r - i + 1,f(x / i)));
        i = r;
    }
    res = inc(res,x);
    res = mul(res,Inv2);
    return res;
}
void Solve() {
    phi[1] = 1;S[1] = 1;
    for(int i = 2 ; i <= MAXN ; ++i) {
        if(!nonprime[i]) {
            prime[++tot] = i;
            phi[i] = i - 1;
        }
        for(int j = 1 ; j <= tot ; ++j) {
            if(prime[j] > MAXN / i) break;
            nonprime[prime[j] * i] = 1;
            if(i % prime[j] == 0) {phi[i * prime[j]] = phi[i] * prime[j];break;}
            else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
        }
        S[i] = inc(S[i - 1],mul(phi[i],i));
    }
    Inv2 = (MOD + 1) / 2;
    Inv6 = 1LL * Inv2 * (MOD + 1) / 3 % MOD; 
    int a,b;
    read(a);read(b);
    out(inc(calc(b),MOD - calc(a - 1)));enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

【51nod】1227 平均最小公倍数

标签:put   div   prim   source   efi   数论   TE   add   type   

原文地址:https://www.cnblogs.com/ivorysi/p/9157831.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!