zoukankan      html  css  js  c++  java
  • Luogu P2303 [SDOi2012]Longge的问题 题解

    题目

    解题思路

    gcd(i,n)的值一定是n的一个约数,并且n的约数个数并不大(好像不会超过5000)

    由此可以想到枚举n的每个约数p,再求出gcd(i,n)的值为p的i的个数num,答案res就为p*num的和

    因此只要求出对于每个P满足要求的i的个数即可解决问题

    设当gcd(i,n)为p时,i=p·k1,n=p·k2.易得此时k1,k2互质

    求与一个数互质的数的个数?这正是欧拉函数解决的问题

    由于n的约数很少(计算次数少),不需要用欧拉函数的递推式,直接按照公式计算就可以了

    代码

    #include <stdio.h>
    #include <cmath>
    using namespace std;
    #define ll long long
    const int N = 1e5;
    ll n, tot, res, h, k[N], p[N];
    inline ll P (ll x) { return x * x; }
    inline void Pre_work () {        //素数线性筛模板 
    	for (int i = 2; P(i) <= n; ++i) {
    		if (!k[i]) p[++tot] = i;
    		for (int j = 1; j <= tot and P (i * p[j]) <= n; ++j) {
    			k[i * p[j]] = 1;
    			if (i % p[j] == 0) break;
    		}
    	}
    }
    inline ll f (ll x) {
    	ll res (x);
    	for (int i = 1; i <= tot and p[i] <= x; ++i)    //套用欧拉公式计算 
    	  if (x % p[i] == 0) {
    	  	res = res * (p[i] - 1) / p[i]; 
    	  	while (x % p[i] == 0) x /= p[i];
    	  }
    	return res * (x - 1 + (x == 1)) / x;        //最后x可能是个质数,要再计算一次( x为 1时需要特判) 
    }
    int main() {
    	scanf ("%lld", &n);
    	Pre_work ();     //找出1——sqrt(n)的素数 
    	for (int i = 1; P(i) <= n; ++i)   //找出 n的约数 
    		if (n % i == 0) res += i * f (n / i) + (P(i) != n) * n / i * f (i); //如果i*i==n要特判防止重复计算 
    	printf ("%lld
    ", res);
    	return 0;
    }
    
  • 相关阅读:
    OOP & Pointer: Segment Tree
    ICPC_2020 上海站
    Notes: Kirchhoff's Matrix 基尔霍夫矩阵
    CS61A Homework: Church Numerals
    题解:[COCI2011-2012#5] BLOKOVI
    题解:SDOI2017 新生舞会
    题解:POI2012 Salaries
    题解:洛谷P1357 花园
    题解:CF593D Happy Tree Party
    题解 P2320 【[HNOI2006]鬼谷子的钱袋】
  • 原文地址:https://www.cnblogs.com/whx666/p/11926741.html
Copyright © 2011-2022 走看看