由于博主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;
}