zoukankan      html  css  js  c++  java
  • 【题解】[SDOI2012] Longge 的问题

    题目信息

    题目来源:CCF 山东省选 2012;

    在线评测地址:Luogu#2303

    运行限制:时间不超过 (3.00 extrm{s}),空间不超过 (128 extrm{MiB})

    题目背景

    Longge 的数学成绩非常好,并且他非常乐于挑战高难度的数学问题。

    题目描述

    现在问题来了:给定一个整数 (n),你需要求出 (sumlimits_{i=1}^n gcd(i,n)),其中 (gcd(i,n)) 表示 (i)(n) 的最大公因数。

    输入格式

    输入只有一行一个整数,表示 (n)

    输出格式

    输出一行一个整数表示答案。

    数据规模与约定

    • 对于 (60\%) 的数据,保证 (nle 2^{16})
    • 对于 (100\%) 的数据,保证 (1le nle 2^{32})

    分析

    这道题太经典了,以至于后面的很多数论题都是模仿这个形式的。

    (60 exttt{pts})

    暴力求即可,复杂度 (mathcal{O}(nlog n))

    (100 exttt{pts})

    我们要推一下式子,来优化这个算法。

    [egin{aligned} sumlimits_{i=1}^n gcd(i,n)=&sumlimits_{i=1}^n sumlimits_{d|n}dleft[[d|i]landleft[gcdleft(frac{i}{d},frac{n}{d} ight)=1 ight] ight]\ =&sumlimits_{d|n}dsumlimits_{d|i}left[gcdleft(frac{i}{d},frac{n}{d} ight)=1 ight]\ =&sumlimits_{d|n}dvarphileft(frac{n}{d} ight) end{aligned} ]

    枚举所有因数,计算即可,复杂度 (mathcal{O}(sigma(n)sqrt{n})),可以 AC。

    Bonus

    当然,这道题这么数学,其实有更好的做法,可以做到 (mathcal{O}(sqrt{n})) 的优秀复杂度。

    具体内容可以看这一篇文章。

    注意事项

    这道题非常细节,很容易不知不觉就 WA、TLE。

    边界问题

    看到那个数据范围 (le 2^{32}) 没有?(n) 是可以等于 (2^{32}) 的,所以别忘了开 long long

    当然所有中间变量都得开 long long,否则会出现溢出。

    同时,判定质数时注意平方数情况。

    特判问题

    (varphi(n)) 时,得先判质数,然后进行质因数分解。

    同时,质因数分解时循环也只能开到 (sqrt{n}) 级别,最后还要特判是否有没有除掉的数。否则一个 (2 imes (2^{31}-1)) 就能卡得飞起。

    还有,你有没有把 (1) 判为质数呢?特判一定要加!

    Code

    经过了,这道题终于 (color{GreenYellow}{ exttt{AC}}) 了。

    #include <cstdio>
    using namespace std;
    
    typedef long long ll;
    
    ll phi(ll x) // 计算
    {
    	ll ans = 1;
    	bool flag = false;
    
    	for (ll i = 2; i * i <= x; i++) // 判质数
    		if (!(x % i))
    		{
    			flag = true;
    			break;
    		}
    	
    	if (!flag && x != 1) // 是质数
    		return x - 1; // 退出
    
    	for (ll i = 2; i * i <= x; i++) // 否则就开始找质因数
    		if (!(x % i)) // 找到了
    		{
    			ans *= (i - 1), x /= i; // 计算贡献
    			while (!(x % i))
    				x /= i, ans *= i;
    		}
    	
    	if (x != 1) // 还没算干净,一定是质数
    		ans *= x - 1; // 直接计算贡献
    	
    	return ans; // 返回答案
    }
    
    int main()
    {
    	ll n, ans = 0;
    
    	scanf("%lld", &n); // 输入
    	for (ll i = 1; i * i <= n; i++) // 筛因数
    		if (!(n % i)) // 找到了(一对)
    		{
    			ans += phi(i) * (n / i); // 计算一个
    			if (i * i < n) // 不是平方数
    				ans += phi(n / i) * i; // 就再计算一个。
    		}
    	
    	printf("%lld
    ", ans); // 输出
    
    	return 0; // 然后就 AC 了、
    }
    
  • 相关阅读:
    实验十二:面向对象基础 5、构造方法、重载
    实验十一:面向对象基础 3、类、对象、方法实训
    实验十:程序结构与数组 8、数组实训
    实验九:程序结构与数组 6、方法实训
    课后作业:情境三:程序结构与数组 5、方法
    Java获取随机数
    实验八:程序结构与数组 4、循环实训
    情境三:程序结构与数组 4、循环实训
    ES查询优化
    ES配置搜索规则
  • 原文地址:https://www.cnblogs.com/5ab-juruo/p/solution-sdoi2012_lg2303.html
Copyright © 2011-2022 走看看