线性筛学习

由于博主Niconicoqaq太菜了,导致这个在搞OI时就应该搞懂的东西,现在才差不多彻底搞懂了。。。QAQ

果然还是jzp神犇的PPT好懂。。。https://wenku.baidu.com/view/2d706761aa00b52acec7ca63.html?from=search

 

第一道(hdu1215):http://acm.hdu.edu.cn/showproblem.php?pid=1215

题目就是让你求一个数的所有因子之和。

题解:

手推式子

i为质数:ans[i]=1;

i%prime[j]=0 ans[i*prime[j]]=ans[i]+ans[(i*prime[j])/s1]*s1+i; (s1为i*prime[j]中prime[j]的最大次方)

i%prime[j]!=0 ans[i*prime[j]]=ans[i]+i+ans[i]*prime[j];

#include<bits/stdc++.h>
#define MAXN 500010
using namespace std;
int ans[MAXN],prime[MAXN],tot;
bool vis[MAXN];
void Get()
{
	int i,j,gs,s1,ii;
	ans[1]=0;vis[1]=true;
	for(i=2;i<=500000;i++)
	{
		if(vis[i]==false)
		{
			vis[i]=true;
			ans[i]=1;
			prime[++tot]=i;
		}
		for(j=1;j<=tot;j++)
		{
			if(i*prime[j]>500000)break;
			vis[i*prime[j]]=true;
			if(i%prime[j]==0)
			{
				gs=0;s1=prime[j];ii=i;
				while(ii%prime[j]==0){gs++;ii/=prime[j];s1*=prime[j];}
				ans[i*prime[j]]=ans[i]+ans[(i*prime[j])/s1]*s1+i;
				break;
			}
			ans[i*prime[j]]=ans[i]+i+ans[i]*prime[j];
		}
	}
}
int main()
{
	int T,n;
	scanf("%d",&T);
	Get();
	while(T--)
	{
		scanf("%d",&n);
		printf("%d\n",ans[n]);
	}
	return 0;
}

 

 

第二道(hdu2841):http://acm.hdu.edu.cn/showproblem.php?pid=2841

题目让求 i:1->m j:1->n gdc(i,j)=1 的个数

题解:

莫比乌斯反演

黄学长的题解(鏼爷的题解) : http://hzwer.com/4205.html  虽然是另外一题的,但式子推的很清楚.

#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL mu[100010],qzh[100010],prime[100010],lp;
bool vis[100010];
void Get()
{
	int i,j;
	mu[1]=1LL;vis[1]=true;
	for(i=2;i<=100000;i++)
	{
		if(vis[i]==false)
		{
			prime[++lp]=i;
			mu[i]=-1LL;
		}
		for(j=1;j<=lp;j++)
		{
			if(i*prime[j]>100000)break;
			vis[i*prime[j]]=true;
			if(i%prime[j]==0)
			{
				mu[i*prime[j]]=0LL;
				break;
			}
			mu[i*prime[j]]=-mu[i];
		}
	}
}
void Qzh()
{
	int i;
	for(i=1;i<=100000;i++)qzh[i]=qzh[i-1]+mu[i];
}
LL calc(LL m,LL n)
{
	LL ans=0,mn=min(m,n),d,p;
	for(d=1;d<=mn;d=p+1)
	{
		p=min(m/(m/d),n/(n/d));
		ans+=(qzh[p]-qzh[d-1])*(m/d)*(n/d);
	}
	return ans;
}
int main()
{
	LL T,m,n;
	Get();Qzh();
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%lld %lld",&m,&n);
		printf("%lld\n",calc(m,n));
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值