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 了、
    }
    
  • 相关阅读:
    .net core 3.1 使用Redis缓存
    JavaSE 高级 第11节 缓冲输入输出字节流
    JavaSE 高级 第10节 字节数组输出流ByteArrayOutputStream
    JavaSE 高级 第09节 字节数组输入流ByteArrayInputStream
    JavaSE 高级 第08节 文件输出流FileOutputStream
    JavaSE 高级 第07节 文件输入流FileInputStream
    JavaSE 高级 第06节 初识I、O流
    JavaSE 高级 第05节 日期类与格式化
    JavaSE 高级 第04节 StringBuffer类
    JavaSE 高级 第03节 Math类与猜数字游戏
  • 原文地址:https://www.cnblogs.com/5ab-juruo/p/solution-sdoi2012_lg2303.html
Copyright © 2011-2022 走看看