zoukankan      html  css  js  c++  java
  • 【题解】Loj6053 简单的函数

    Link

    ( ext{Solution:})

    显然的 Min_25 筛。因为题目已经告诉我们:函数是积性函数,并且素数及其次幂处的点值可以快速计算。

    先把给的函数拆成若干完全积性函数的和:我们观察到,当 (p) 为质数的时候, (f(p)=p-1.) 所以我们可以把函数拆成 (f(p)=p,f(p)=1) 这两个来分别计算出 (g_1(n,j),g_2(n,j)) 数组。

    但是对于 (2) 这个性质不成立怎么办?考虑计算答案的时候去掉影响就可以了,先按照 (1) 算即可。

    于是线性筛的时候我们需要维护一下素数的和,至于 (1) 这一部分自己算也行,为了板子化也可以求一下前缀和。

    同样地,记录下基本和组,并把所有数都当成质数来计算 (g,) 因为最后用到的只有素数的部分。

    考虑合并答案,实际上就是一样的式子:不断提出 (p[i]) 直到把因子提干净,一步步计算即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int mod=1e9+7;
    const int N=2e5+10;
    inline int Add(int x,int y) {
    	return (x+y)%mod;
    }
    inline int Mul(int x,int y) {
    	return 1ll*x*y%mod;
    }
    inline int dec(int x,int y) {
    	return (x-y+mod)%mod;
    }
    bool vis[N];
    int p[N],sum1[N],cnt,sq,sp,id1[N],id2[N],g1[N],n,g2[N],w[N],m,sum2[N];
    void pre() {
    	for(int i=2; i<=sq; ++i) {
    		if(!vis[i])p[++cnt]=i;
    		for(int j=1; j<=cnt&&i*p[j]<=sq; ++j) {
    			vis[i*p[j]]=1;
    			if(i%p[j]==0)break;
    		}
    	}
    	for(int i=1; i<=cnt; ++i) {
    		sum2[i]=Add(sum2[i-1],p[i]);
    		sum1[i]=sum1[i-1]+1,sum1[i]%=mod;
    	}
    }
    inline int f2(int x) {
    	x%=mod;
    	return x*(x+1)/2%mod;
    }
    inline int getid(int x) {
    	if(x<=sq)return id1[x];
    	return id2[n/x];
    }
    inline int S(int x,int j) {
    	if(p[j]>x)return 0;
    	int Ans=dec(dec(g2[getid(x)],g1[getid(x)]),dec(sum2[j],sum1[j]));
    	if(j==0&&x>=2)Ans=Add(Ans,2);
    	for(int i=j+1; i<=cnt&&p[i]*p[i]<=x; ++i) {
    		for(int e=1,sp=p[i]; sp<=x; sp*=p[i],++e) {
    			Ans=Add(Ans,Mul((p[i]^e)%mod,Add(S(x/sp,i),(e>1))));
    		}
    	}
    	return Ans;
    }
    signed main() {
    	scanf("%lld",&n);
    	sq=sqrt(n);
    	pre();
    	for(int l=1,r; l<=n; l=r+1) {
    		int d=n/l;
    		r=n/d;
    		w[++m]=d;
    		g1[m]=(w[m]-1+mod)%mod;
    		g2[m]=f2(w[m])-1;
    		g2[m]+=mod;g2[m]%=mod;
    		if(w[m]<=sq)id1[w[m]]=m;
    		else id2[r]=m;
    	}
    	for(int i=1; i<=cnt; ++i) {
    		for(int j=1; j<=m&&p[i]*p[i]<=w[j]; ++j) {
    			g1[j]=dec(g1[j],dec(g1[getid(w[j]/p[i])],sum1[i-1]));
    			g2[j]=dec(g2[j],Mul(p[i],dec(g2[getid(w[j]/p[i])],sum2[i-1])));
    		}
    	}
    	printf("%lld
    ",(S(n,0)+mod+1)%mod);
    	return 0;
    }
    
  • 相关阅读:
    我的浏览器收藏夹分类
    我的浏览器收藏夹分类
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
  • 原文地址:https://www.cnblogs.com/h-lka/p/15081280.html
Copyright © 2011-2022 走看看