zoukankan      html  css  js  c++  java
  • 【BZOJ4804】欧拉心算(欧拉函数)

    点此看题面

    大致题意:(sum_{i=1}^nsum_{j=1}^nphi(gcd(i,j)))

    前言

    (Jan 28th)刷题计划(1/6),算法标签:莫比乌斯反演&杜教筛(强烈投诉,思路直接被这个算法标签带歪了,其实根本用不到莫比乌斯反演啊......)。

    这道题其实是很套路的,和【CCPC-Wannafly Winter Camp Day3 (Div1) F】小清新数论这道题很像,而且由于数据范围还能省去杜教筛。

    欧拉函数

    强调:这道题完全不需要用到(mu)

    考虑按照做这种题的经典套路,我们枚举(gcd),得到:

    [sum_{d=1}^nphi(d)sum_{i=1}^{lfloorfrac nd floor}sum_{j=1}^{lfloorfrac nd floor}[gcd(i,j)==1] ]

    看到后面这个([gcd(i,j)==1])的式子,是不是立马有一种反演的冲动?

    然而,如果此时你选择了反演,最终将得到一个很麻烦的式子,因此我们采取另一种做法。

    现单独考虑(sum_{i=1}^{lfloorfrac nd floor}sum_{j=1}^{lfloorfrac nd floor}[gcd(i,j)==1])这个式子。

    如果(i<j),那么交换(i,j),就唯一对应一种(i>j)的情况。

    如果(i=j),那么当且仅当(i=j=1)时,(gcd(i,j)=1)

    所以我们把它转化成只考虑(ige j)的情况,这个式子就等同于:

    [sum_{i=1}^{lfloorfrac nd floor}(2sum_{j=1}^{i}[gcd(i,j)==1]-1) ]

    其中之所以要减(1),是因为(i=j=1)的情况被重复算了两遍。

    然后我们发现式子中的(sum_{j=1}^{i}[gcd(i,j)==1])就相当于是(phi(i))(这就是欧拉函数的定义)。

    所以,原式就被化简为:

    [sum_{d=1}^nphi(d)sum_{i=1}^{lfloorfrac nd floor}(2phi(i)-1) ]

    于是我们对(phi)做一个前缀和,接下来就是很套路的除法分块了。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 10000000
    using namespace std;
    int n;
    template<int SZ> class LinearSieve//线性筛
    {
    	private:
    		int Pt,P[SZ+5],phi[SZ+5];long long s[SZ+5];
    	public:
    		I long long operator [] (CI x) Con {return s[x];}
    		I LinearSieve()
    		{
    			RI i,j;for(phi[1]=s[1]=1,i=2;i<=SZ;++i)
    			{
    				!P[i]&&(phi[P[++Pt]=i]=i-1),s[i]=s[i-1]+phi[i];
    				for(j=1;j<=Pt&&i*P[j]<=SZ;++j)
    					if(P[i*P[j]]=1,i%P[j]) phi[i*P[j]]=phi[i]*(P[j]-1);
    					else {phi[i*P[j]]=phi[i]*P[j];break;}
    			}
    		}
    };LinearSieve<N> Phi;
    int main()
    {
    	RI Tt,l,r;long long t;scanf("%d",&Tt);W(Tt--)
    	{
    		for(scanf("%d",&n),t=0,l=1;l<=n;l=r+1)//除法分块
    			r=n/(n/l),t+=(Phi[r]-Phi[l-1])*(2*Phi[n/l]-1);
    		printf("%lld
    ",t);
    	}return 0;
    }
    
  • 相关阅读:
    SWTDesigner注册器
    C# 创建、部署和调用WebService的简单示例
    (android实战)应用在线版本更新
    jQuery获取Select选择的Text和 Value(转)
    Android 判断sd卡和sim卡是否可用
    Android开发中如何固定屏幕显示!
    入侵网站简单方法总结
    【Android】防止UI界面被输入法遮挡(画面随输入法自适应)
    关于字符编码的问题
    最好用的mysql密码忘记的解决方法
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4804.html
Copyright © 2011-2022 走看看