zoukankan      html  css  js  c++  java
  • P1891 疯狂LCM

    (color{#0066ff}{ 题目描述 })

    众所周知,czmppppp是数学大神犇。一天,他给众蒟蒻们出了一道数论题,蒟蒻们都惊呆了。。。

    给定正整数N,求LCM(1,N)+LCM(2,N)+...+LCM(N,N)。

    (color{#0066ff}{输入格式})

    第一行一个数T,表示有T组数据。

    对于每组数据,一行,一个正整数N。

    (color{#0066ff}{输出格式})

    T行,每行为对应答案。

    (color{#0066ff}{输入样例})

    3
    1
    2
    5
    

    (color{#0066ff}{输出样例})

    1
    4
    55
    

    (color{#0066ff}{数据范围与提示})

    对于30%的数据,1≤T≤5,1≤N≤100000

    对于100%的数据,1≤T≤300000,1≤N≤1000000

    (color{#0066ff}{ 题解 })

    题目要求

    [sum_{i=1}^n lcm(i,n) ]

    转为gcd形式

    [n*sum_{i=1}^n frac{i}{gcd(i,n)} ]

    枚举gcd

    [sum_{d=1}^n nsum_{i=1}^n [gcd(i,n)==d] frac i d ]

    把d弄前面去

    [nsum_{d|n}sum_{i=1}^{lfloorfrac n d floor} [gcd(i,frac n d)==1] i ]

    额,后面的的东西就是与一个数互质的数的和

    但是我们只能求个数

    考虑若(gcd(i,n)=1),则(gcd(n-i,n)=1)

    显然i一定成对出现

    要特判一下1

    所以,原式可以变为

    [nsum_{d|n} frac {varphi(lfloorfrac n d floor)*lfloorfrac n d floor + 1} {2} ]

    这样最后的复杂度是(O(Tsqrt n))

    不太好卡进去

    因为时间浪费在了枚举因子

    看到题目n的范围,显然可以开一个数组记录n的答案

    这样是(O(T+nsqrt n))

    考虑枚举倍数,减少无用枚举

    (O(T+nlogn))可过

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int maxn = 1e6 + 10;
    LL ans[maxn], phi[maxn], pri[maxn], tot;
    bool vis[maxn];
    LL getans(LL n) {
    	return (phi[n] * n + 1) >> 1;
    }
    void predoit() {
    	phi[1] = 1;
    	for(int i = 2; i < maxn; i++) {
    		if(!vis[i]) pri[++tot] = i, phi[i] = i - 1;
    		for(int j = 1; j <= tot && (LL)i * pri[j] < maxn; j++) {
    			vis[i * pri[j]] = true;
    			if(i % pri[j] == 0) {
    				phi[i * pri[j]] = phi[i] * pri[j];
    				break;
    			}
    			else phi[i * pri[j]] = phi[i] * (pri[j] - 1);
    		}
    	}
    	for(int i = 1; i < maxn; i++)
    		for(int j = i; j < maxn; j += i) 
    			ans[j] += getans(j / i);
    }
    int main() {
    	predoit();
    	for(int T = in(); T --> 0;) {
    		LL n = in();
    		printf("%lld
    ", n * ans[n]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    PCI 设备详解二
    PCI 设备详解一
    SKBUFFER详解
    windows中的进程和线程
    sVIrt概述
    qemu网络虚拟化之数据流向分析二
    在VC6的debug框里面输出版权信息
    [yii]Trying to get property of non-object
    yii使用CFrom调用ajax失败的记录
    VC代码生成里面的/MT /MTd /MD /MDd的意思
  • 原文地址:https://www.cnblogs.com/olinr/p/10299353.html
Copyright © 2011-2022 走看看