洛谷 P4213 【模板】杜教筛(Sum)(杜教筛)

 

洛谷 P4213 【模板】杜教筛(Sum)(杜教筛)_第1张图片

输入输出样例

输入样例#1:

6
1
2
8
13
30
2333

输出样例#1:

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

大佬博客:https://www.cnblogs.com/peng-ym/p/9446555.html(证明 、推导全都有,一些常用的函数要记住。简直好文。)

写一下需要记的公式吧:

h=g*f,g为自己要找的数论函数,f为题目所给函数。

结论:g(1)S(n)=\sum_{i=1}^{n}h(i)-\sum_{d=2}^{n}g(d)*S(\left \lfloor \frac{n}{d} \right \rfloor),S(n)为所求函数的前缀和。

实现:首先,筛一个合适常数内的值,然后大于该范围是分块递归求。

#include  
#include 
#define ll long long
#define ull unsigned long long 
using namespace std;
const int N = 5e6+10;
int phi[N],mu[N],prime[N],cnt;
int pre[N];
ll pre1[N];
tr1::unordered_map  mp,mp1; 
templateinline void read(T &x)
{
    x=0;
    static int p;p=1;
    static char c;c=getchar();
    while(!isdigit(c)){if(c=='-')p=-1;c=getchar();}
    while(isdigit(c)) {x=(x<<1)+(x<<3)+(c-48);c=getchar();}
    x*=p;
}
void Init()
{
	cnt=0;
	phi[1]=mu[1]=1;
	for(int i=2;i<=N-10;i++)
	{
		if(!phi[i])
		{
			prime[cnt++]=i;
			phi[i]=i-1;
			mu[i]=-1;
		}
		for(int j=0;j=0&&l<=n;l=r+1)
	{
		r=n/(n/l);
		ans-=(r-l+1)*S1(n/l); 
	} 
	return mp1[n]=ans; 
}
int main(void)
{
	Init();
	int t,n;
	scanf("%d",&t);
	while(t--)
	{
		read(n); 
		printf("%lld %d\n",S1(n),S(n));	
	}
	return 0;	
} 
/*
6
1526968
255555555
1000000000
999999999
2000000000
1999999999
*/


 

 

你可能感兴趣的:(=====数论=====)