zoukankan      html  css  js  c++  java
  • 【bzoj2401】陶陶的难题I “高精度”+欧拉函数+线性筛

    题目描述

    输入

    第一行包含一个正整数T,表示有T组测试数据。接下来T<=10^5
    行,每行给出一个正整数N,N<=10^6。 

    输出

    包含T行,依次给出对应的答案。

    样例输入

    7
    1
    10
    100
    1000
    10000
    100000
    1000000

    样例输出

    1
    2127
    18446224
    183011304660
    1827127167830060
    18269345553999897648
    182690854273058293758232


    题解

    “高精度”+欧拉函数+线性筛

    由于$i$和$j$的范围都是$1$到$n$,因此可以先只计算$jle i$的情况,然后乘2,再减去多算的$i=1$即为题目中$1$到$n$的情况。

    $ sumlimits_{i=1}^nsumlimits_{j=1}^ilcm(i,j)\=sumlimits_{i=1}^nsumlimits_{d|i}sumlimits_{j=1}^i[gcd(i,j)=d]frac{ij}d\=sumlimits_{i=1}^nsumlimits_{d|i}sumlimits_{j=1}^{frac id}[gcd(frac id,j)=1]ij\=sumlimits_{i=1}^nisumlimits_{d|i}sumlimits_{j=1}^{frac id}[gcd(frac id,j)=1]j\=sumlimits_{i=1}^nisumlimits_{d|i}sumlimits_{j=1}^{d}[gcd(d,j)=1]j$

    而考虑$sumlimits_{j=1}^d[gcd(d,j)=1]j$的实际含义:$1sim d$中所有与$d$互质的数的和。考虑当$d>1$时,如果$j$与$d$互质,那么$d-j$与$d$也一定互质。因此与$d$互质的数一定是成对出现的,每对的和为$d$,故它们的和为$frac{dvarphi(d)}2$。注意这个公式在$d=1$时不成立,需要特判

    于是就有:

    $ sumlimits_{i=1}^nisumlimits_{d|i}sumlimits_{j=1}^{d}[gcd(d,j)=1]j\=frac{sumlimits_{i=1}^ni(sumlimits_{d|i}dvarphi(d)+1)}2$

    于是所求即为:

    $2·frac{sumlimits_{i=1}^ni(sumlimits_{d|i}dvarphi(d)+1)}2-sumlimits_{i=1}^ni=sumlimits_{i=1}^nisumlimits_{d|i}dvarphi(d)$

    (其中很多乱七八糟的东西都消掉了,剩下的式子非常优美)

    然后$f(i)=sumlimits_{d|i}dvarphi(d)$是积性函数,因此可以快筛。

    当然,此时$i$与$prime[j]$不互质时没有很好的通用方法,只好使用快筛的通法:设$n=vp^a$,那么$f(n)=f(v)*f(p^a)$,此时只需要维护每个数的$p$和$p^a$即可使用等比数列求和公式$O(1)$求出:

    $f(p^a)=frac{p^{2a+1}+1}{p+1}$

    然后就可以维护$i·f(i)$的前缀和,然后$O(1)$回答询问。

    然而本题最恶心之处:本题爆long long!因此必须使用中精度,即两个long long拼起来,每个long long12位。当然,只需要在求前缀和时使用中精度,其它地方long long即可。

    时间复杂度$O(n+T)$

    #include <cstdio>
    #define N 1000010
    #define k 1000000
    typedef long long ll;
    ll f[N] , sx[N] , sy[N];
    int w[N] , v[N] , prime[N] , tot , np[N];
    int main()
    {
    	int i , j , t , T , n;
    	f[1] = 1;
    	for(i = 2 ; i <= k ; i ++ )
    	{
    		if(!np[i]) w[i] = v[i] = i , f[i] = (ll)i * i - i + 1 , prime[++tot] = i;
    		for(j = 1 ; j <= tot && (t = i * prime[j]) <= k ; j ++ )
    		{
    			np[t] = 1;
    			if(i % prime[j] == 0)
    			{
    				w[t] = w[i] , v[t] = v[i] * w[i] , f[t] = ((ll)v[t] * v[t] * w[t] + 1) / (w[t] + 1) * f[t / v[t]];
    				break;
    			}
    			else w[t] = v[t] = prime[j] , f[t] = f[i] * f[prime[j]];
    		}
    	}
    	for(i = 1 ; i <= k ; i ++ ) sx[i] = sx[i - 1] + i * f[i] , sy[i] = sy[i - 1] + sx[i] / 1000000000000ll , sx[i] %= 1000000000000ll;
    	scanf("%d" , &T);
    	while(T -- )
    	{
    		scanf("%d" , &n);
    		if(sy[n]) printf("%lld%012lld
    " , sy[n] , sx[n]);
    		else printf("%lld
    " , sx[n]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Linux-文件编程
    Linux-编程基础
    Linux-系统管理
    Linux-命令
    图解HTTP-笔记
    微信小程序发送红包功能。填坑记录
    PHP中使用raw格式发送POST请求
    论一个PHP项目上线的注意点
    PHP CURL 模拟form表单上传遇到的小坑
    使用php的curl函数post返回值为301永久迁移的问题。(301 Moved Permanently)
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7517464.html
Copyright © 2011-2022 走看看