没错,傻X博主只是吸引你点进来的,我TM不会正解,60暴力送上
#include <cstdio>
#include <iostream>
using namespace std;
const int N=99999999;
int phi[N+10],prime[N+10];
int tot;
bool mark[N+10];
long long getphi(int n)
{
phi[1]=1;
long long ans=1;
for(int i=2;i<=n;i++)
{
if(!mark[i])
{
prime[++tot]=i;
phi[i]=i-1;//性质1
ans+=phi[i];
}
for(int j=1;j<=tot&&i*prime[j]<=n;j++)
{
mark[i*prime[j]]=1;
if(!(i%prime[j]))
{
phi[i*prime[j]]=phi[i]*prime[j];//性质2
ans+=phi[i*prime[j]];
break;
}
else
phi[i*prime[j]]=phi[i]*(prime[j]-1),ans+=phi[i*prime[j]];
}
}
return ans;
}
int main()
{
int n;
scanf("%d",&n);
printf("%lld",getphi(n));
return 0;
}
没有发现进度条不对吗!
往下看的人才是勇士啊,傻X博主其实给了正解。
前提
∑ni=1
∑d|i
φ(n)=
∑ni=1
∑⌊n/d⌋i=1
φ(i)=
∑nd=1
s(
⌊n/d⌋
)=(n*(n+1))/2
所以s(n)=(n*(n+1))/2-
∑nd=2
s(
⌊n/d⌋
)
s我们先预处理出1e7以内的,大的用上面的式子递归实现即可
#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const int N=1e7+1;
ll phi[N+10],prime[N+10];
int tot;
bool mark[N+10];
void getphi(int n)
{
phi[1]=1;
for(int i=2;i<=n;i++)
{
if(!mark[i])
{
prime[++tot]=i;
phi[i]=i-1;//性质1
}
for(int j=1;j<=tot&&i*prime[j]<=n;j++)
{
mark[i*prime[j]]=1;
if(!(i%prime[j]))
{
phi[i*prime[j]]=phi[i]*prime[j];//性质2
break;
}
else
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for(int i=2;i<=n;i++)
phi[i]+=phi[i-1];
}
ll work(int n)
{
if(n<=N) return phi[n];
ll ans=0;int pos;
for(int i=2;i<=n;i=pos+1)
{
pos=n/(n/i);//向下取整,很长一段是相同的
ans+=(pos-i+1)*work(n/i);
}
return (ll)n*(n+1)/2-ans;
}
int main()
{
int n;
getphi(N);
scanf("%d",&n);
printf("%lld",work(n));
return 0;
}