Min_25筛(LibreOJ #6053: 简单的函数)

 

一个简单的问题:求\sum_{i=1}^{n}i^k (i为质数)

设小于\small \sqrt{n}的质数有t个,其中p_{i}表示第i个质数

再设 S(x, y) =\sum_{i=2}^{x}i^k (i为质数或者i的最小质因子不小于p_{y})

 

那么有

  • S(x,y)=S(x,y-1)-p_{y}^{k}[S(\left \lfloor \frac{x}{p_y} \right \rfloor,y-1)-\sum_{i=1}^{j-1}p_{i}^{k}]     (p_{j}^{2}\leq x)
  • S(x, y)=S(x,y-1)     (p_j^2>x)

其中 S(n,0)=\sum_{i=2}^n i^kS(n,p_t)  就是答案

因为每次S(x, y)都是由S(?, y-1)转移过来,而有效的"?"只有\small \sqrt{n}个,所以总体复杂度小于O(n)

 

 

第二个问题:已知F(x)是积性函数,且当p为质数时 F(p^k)=kp,求\sum_{i=1}^nF(i)

积性函数很重要的性质(引用)先写在前面:

仍然考虑求 S_f(n,y)=\sum_{i=2}^nF(i)  (i的最小质因子不小于p_y)

那么答案就是S_f(n,1)+F(1)

 

考虑用上图中的性质①来求S_f(n,y)

首先把所有满足p为质数且p\geqslant p_yF(p^k)全部加上

得到:S_f(n,y)=S(n,p_t)-\sum_{i=1}^{y-1}p_i+\sum_{i=y}^t\sum_{e=2}^{p^e\leqslant n}F(p_i^e)(第一部分)

之后再将所有剩下的F()加上,也就是把所有满足x质因子不止一个的F(x)加上

得到:S_f(n,y)=S_f(n,y)+\sum_{i=y}^t\sum_{e=1}^{p^{e+1}\leqslant n}F(p_i^e)S(\left \lfloor \frac{n}{p_i^e} \right \rfloor,y+1) (第二部分)搞定!

这个可以用递归来实现,复杂度约为O(n^{1-c}),c为一个满足1>c>0.25的常数

 

 

第三个问题:LibreOJ: 6053. 简单的函数

 

这道题和第二道题的唯一区别就是当p为质数时,f(p^k)值不同

这样子的话,对于S_f(n,y)第二部分算法并没有变,变的是第一部分算法

→仔细分析一下,当p为不为2的质数的时候,F(p)=p-1

→所以只需要在第一部分算法后面多减掉质数的个数即可!其中p为2的时候要特判,因为此时F(2) = 3

具体看程序

 

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
#define er 500000004
int cnt, s[200005], S[200005], id[200005], B, m, h[200005];
bool flag[200005];
LL n, w[200005], pri[200005];
void Primeset(int n)
{
	int i, j;
	for(i=2;i<=n;i++)
	{
		if(flag[i]==0)
		{
			pri[++cnt] = i;
			s[cnt] = (s[cnt-1]+i)%mod;
		}
		for(j=1;j<=cnt&&i*pri[j]<=n;j++)
		{
			flag[i*pri[j]] = 1;
			if(i%pri[j]==0)
				break;
		}
	}
}
//S_f(n,y)=S(n,p_t)-\sum_{i=1}^{y-1}p_i+\sum_{i=y}^t\sum_{e=2}^{p^e\leqslant n}F(p_i^e)
LL F(LL x, int y)
{
	LL t1;
	int i, k, e, ans;
	if(x<=1 || pri[y]>x)
		return 0;
	if(x>B)
		k = n/x;
	if(x<=B)
		k = id[x];
	//找到k满足w[k]=x
	ans = (S[k]-s[y-1]-(h[k]-(y-1)))%mod;
	if(y==1)
		ans += 2;
	for(i=y;i<=cnt&&(LL)pri[i]*pri[i]<=x;i++)
	{
		t1 = pri[i];
		for(e=1;t1*pri[i]<=x;e++)
		{
			ans = (ans+(F(x/t1, i+1)*(pri[i]^e)%mod+(pri[i]^(e+1)))%mod)%mod;
			t1 *= pri[i];
		}
	}
	return ans;
}

int main(void)
{
	LL i, j, k, last;
	scanf("%lld", &n);
	B = sqrt(n), Primeset(B);
	for(i=1;i<=n;i=last+1)		//初始化
	{
		w[++m] = n/i;
		h[m] = (w[m]-1)%mod;
		S[m] = (1+w[m])%mod*(w[m]%mod)%mod*er%mod-1;
		last = n/(n/i);
		if(n/i<=B)
			id[n/i] = m;
	}
	//id[i]:哪个x满足w[x]等于n/w[i]
	for(j=1;j<=cnt;j++)
	{
		for(i=1;i<=m&&pri[j]*pri[j]<=w[i];i++)
		{
			if(w[i]/pri[j]<=B)
				k = id[w[i]/pri[j]];
			else
				k = n/(w[i]/pri[j]);
			S[i] = (S[i]-(LL)pri[j]*(S[k]-s[j-1])%mod+mod)%mod;
			h[i] = (h[i]-(h[k]-(j-1)))%mod;
		}
	}
	//S[i]:小于等于w[i]所有质数的和
	//h[i]:小于等于w[i]有多少个质数
	printf("%lld\n", (F(n, 1)+1+mod)%mod);
	return 0;
}

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值