zoukankan      html  css  js  c++  java
  • bzoj 4804 欧拉心算

    题面:

    Link

    一句话题意:

    给出 (k) 组询问,每次给你一个 (n) ,让你回答 (displaystylesum_{i=1}^{n}sum_{j=1}^{n}phi(gcd(i,j))

    题解

    下面,又到了我们的颓柿子时间啦。

    我们要求的是这个柿子:

    (displaystylesum_{i=1}^{n}sum_{j=1}^{n}phi(gcd(i,j))

    先枚举一个 (d) 可得:

    (displaystylesum_{d=1}^{n}phi(d) sum_{i=1}^{n}sum_{j=1}^{n} [gcd(i,j) == d])

    后面的那两个求和柿子可以提出一个 (d) 来,变成:

    (displaystylesum_{d=1}^{n} phi(d) sum_{i=1}^{nover d}sum_{j=1}^{nover d} [gcd(i,j) == 1])

    后面的柿子有没有觉得有点熟悉?

    如果你做过 仪仗队 ,你就会一眼把他秒了。

    我们有一个等式: (displaystylesum_{i=1}^{n}sum_{j=1}^{n}[gcd(i,j) == 1] = sum_{i=1}^{n}2 imes phi(i) - 1)

    具体证明:

    首先对于一个 (i), 与他互质的个数 是 (phi(i)) ,又因为 (i,j) 和 (j, i)这两个数对算两个,所以要乘二,减一则是要减去算重复的1.

    对于 (i leq j) 的情况有 (displaystylesum_{i=1}^{n} sum_{j=1}^{i}[gcd(i,j) == 1] = sum_{i=1}^{n} phi(i))

    对于 (i >= j) 的情况同理,最后在减去重复计算的 1

    把这个等式代回原来的柿子,可以化简为:

    (displaystylesum_{d=1}^{n}phi(d) sum_{i=1}^{n over d} 2 imes phi(i) - 1)

    他还可以化为

    (displaystyle(sum_{d=1}^{n} phi(d) (2 imes sum[{n over d}])) - sum[n]))

    对后面的求和柿子,可以预处理出来 (phi) 函数的前缀和。,在用一下数论分块,枚举每个 (d) 即可。

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define LL long long
    const int N = 1e7+10;
    int t,n,m,tot;
    int prime[N],phi[N];
    LL sum[N];
    bool check[N];
    inline int read()
    {
    	int s = 0,w = 1; char ch;
    	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9'){s =s * 10+ch - '0'; ch = getchar();}
    	return s * w;
    }
    void YYCH()
    {
    	phi[1] = 1;
    	for(int i = 2; i <= N-5; i++)//预处理φ函数值
    	{
    		if(!check[i])
    		{
    			prime[++tot] = i;
    			phi[i] = i-1;
    		}
    		for(int j = 1; j <= tot && i * prime[j] <= N-5; j++)
    		{
    			check[i * prime[j]] = 1;
    			if(i % prime[j] == 0)
    			{
    				phi[i * prime[j]] = phi[i] * prime[j];
    			}
    			else
    			{
    				phi[i * prime[j]] = phi[i] * phi[prime[j]];
    			}
    		}
    	}
    	for(int i = 1; i <= N-5; i++)//求前缀和
    	{
    		sum[i] = sum[i-1] + phi[i];
    	}
    }
    LL slove(int n)
    {
    	LL res = 0;
    	for(int l = 1,r; l <= n; l = r + 1)//数论分块
    	{
    		r = n/(n/l);
    		res += 1LL * 2 * (sum[n/l]) * (sum[r]-sum[l-1]);
    	}
    	res -= sum[n];
    	return res;
    }
    int main()
    {
    	t = read(); YYCH();
    	while(t--)
    	{
    		n = read();
    		printf("%lld
    ",slove(n));
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Redis与Memcached的incr/decr差异对比
    Linux sudo用法与配置
    Docker 常用命令
    Linux之间配置SSH互信(SSH免密码登录)
    SVN服务器搭建
    shell中参数的传递
    【代码更新】IIC协议建模——读写EEPROM
    串口完整项目之串口收发字符串
    串口发送模块——1字节数据发送
    状态机设计——从简单的按键消抖开始
  • 原文地址:https://www.cnblogs.com/genshy/p/13669073.html
Copyright © 2011-2022 走看看