• [bzoj3944] Sum


    Description

    img

    Input

    一共T+1行

    第1行为数据组数T(T<=10)

    第2~T+1行每行一个非负整数N,代表一组询问

    Output

    一共T行,每行两个用空格分隔的数ans1,ans2

    Sample Input

    6
    1
    2
    8
    13
    30
    2333
    

    Sample Output

    1 1
    2 0
    22 -2
    58 -3
    278 -3
    1655470 2
    

    solution

    杜教筛模板题无敌卡常题

    先搬出套路式子:

    [S(n)=sum_{i=1}^{n}(f*g)(i)-sum_{i=2}^{n}g(i)S(lfloorfrac{n}{i} floor) ]

    对于(mu(n)),拿一个(I(n)=1)和他卷起来,可以得到:

    [S(n)=1-sum_{i=2}^{n}S(lfloorfrac{n}{i} floor) ]

    对于(varphi(n)),同样拿一个(I(n))卷起来,得到:

    [S(n)=frac{n*(n+1)}{2}-sum_{i=2}^{n}S(lfloorfrac{n}{i} floor) ]

    然后飞速的敲完代码,提交,(TLE)......

    可能是我太弱了,所有的卡常技巧都用上了,然而并没有什么用....

    然后突然发现一个这样的事情:

    对于(varphi(n)),其实可以写成这个样子:

    [varphi(n)=sum_{i=1}^{n}epsilon(gcd(i,n)) ]

    其中(epsilon(n)=[n=1])

    然后苦思冥想无果后闲着无聊对前缀和反演下:

    [egin{align} S(n)&=sum_{i=1}^{n}sum_{d=1}^iepsilon(gcd(d,i))\ &=sum_{i=1}^{n}sum_{d=1}^isum_{d_1|i&d_1|d}mu(d_1)\ &=sum_{i=1}^{n}sum_{d_1|i}sum_{d=1}^{frac{i}{d_1}}mu(d_1)\ &=sum_{i=1}^nsum_{d_1|i}mu(d_1)frac{i}{d_1}\ &=sum_{d_1=1}^nsum_{i=1}^{frac{n}{d_1}}mu(d_1)*i\ &=sum_{d_1=1}^nmu(d_1)*frac{lfloorfrac{n}{d_1} floor(lfloorfrac{n}{d_1} floor+1)}{2} end{align} ]

    然后惊奇的发现,这里面用到的(mu(n))的前缀和正好是第二问要求的,然后这么一来直接快了一倍不止,成功的只跑了(6sAC)

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll long long 
    
    void read(int &x) {
    	x=0;int f=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
    	if(x<0) x=-x,putchar('-');
    	if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 3e6+1;
    
    int pri[maxn],vis[maxn],n,tot,inv2,inv6,mu[maxn];
    
    void sieve() {
    	mu[1]=1;
    	for(int i=2;i<maxn;i++) {
    		if(!vis[i]) pri[++tot]=i,mu[i]=-1;
    		for(int t,j=1;j<=tot&&i*pri[j]<maxn;j++) {
    			vis[t=i*pri[j]]=1;
    			if(!(i%pri[j])) {mu[t]=0;break;}
    			mu[t]=-mu[i];
    		}
    	}
    	//for(int i=1;i<maxn;i++) phi[i]=phi[i-1]+phi[i];
    	for(int i=1;i<maxn;i++) mu[i]=mu[i-1]+mu[i];
    }
    
    map<int,int > Mu;
    
    /*ll sum_phi(int n) {
    	if(n<maxn) return phi[n];
    	if(Phi[n]) return Phi[n];
    	ll T=2,res=1ll*n*(n+1)/2;
    	while(T<=n) {
    		ll pre=T;T=n/(n/T);
    		res=res-1ll*(T-pre+1)*sum_phi(n/T);T++;
    	}
    	return Phi[n]=res;
    	}*/
    
    ll sum_mu(ll n) {
    	if(n<maxn) return mu[n];
    	if(Mu[n]) return Mu[n];
    	ll T=2,res=1;
    	while(T<=n) {
    		ll pre=T;T=n/(n/T);
    		res=res-1ll*(T-pre+1)*sum_mu(n/T);T++;
    	}
    	return Mu[n]=res;
    }
    
    ll sum_phi(ll n) {
    	ll T=1,ans=0;
    	while(T<=n) {
    		ll pre=T;T=n/(n/T);
    		ans+=1ll*(n/pre)*(n/pre+1)/2*(1ll*sum_mu(T)-1ll*sum_mu(pre-1));
    		//printf("%lld %lld
    ",1ll*sum_mu(T)-1ll*sum_mu(pre-1));
    		T++;
    	}
    	return ans;
    }
    
    signed main() {
    	int t,n;read(t);sieve();
    	while(t--) read(n),printf("%lld %lld
    ",sum_phi(n),sum_mu(n));
    	//cerr << (double) clock()/1e6 << endl;
    }
    
    
  • 相关阅读:
    mysql 获取字符串的长度
    mysql 字符类以及重复元字符
    mysql 字段拼接
    mysql 去除字符串中的空格
    mysql 正则表达式
    mysql 选出前五个元素
    mysql regexp 表达式
    mysql 选择所有同学名字
    mysql 获取数学成绩最高以及最低的同学
    mysql 获取单个科目的平均分
  • 原文地址:https://www.cnblogs.com/hbyer/p/10073676.html
Copyright © 2020-2023  润新知