题目传送门:https://www.luogu.org/problem/show?pid=3768
题目分析:我们来看一下,原先题目要我们求:
以下附杜教筛的推导过程:
我们现在要求 f=Id2⋅ϕ (Id指单位函数,即Id(i)=i, ⋅ 为乘法)的前缀和。我们可以发现 f∗Id2=Id3 (其中 ∗ 指狄利克雷卷积),于是令j等于 id :
CODE:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=4600001;
const int M=300509;
typedef long long LL;
struct data
{
LL num;
LL val;
} Hash[M];
LL f[maxn];
bool vis[maxn];
int prime[maxn];
int cur=0;
LL p,n,ans=0;
void Make()
{
f[1]=1;
for (int i=2; iif (!vis[i]) f[i]=i-1,prime[++cur]=i;
for (int j=1; j<=cur && i*prime[j]int k=i*prime[j];
vis[k]=true;
if (i%prime[j]) f[k]=f[i]*f[ prime[j] ];
else
{
f[k]=f[i]*prime[j];
break;
}
}
}
for (int i=2; ilong long)i%p*(long long)i%p;
for (int i=2; i1];
if (f[i]>p) f[i]-=p;
}
}
LL Get3(LL x)
{
LL y;
if (x%2LL) y=((x+1LL)/2LL%p)*(x%p)%p;
else y=(x/2LL%p)*((x+1LL)%p)%p;
y=(y*y)%p;
return y;
}
LL Find(LL x)
{
int y=x%M;
while ( Hash[y].num && Hash[y].num!=x ) y=(y+1)%M;
if (!Hash[y].num) return -1;
return Hash[y].val;
}
LL Get2(LL x)
{
LL y=x+1LL,z=2LL*x+1LL;
bool f2=false,f3=false;
if ( !f2 && !(x%2LL) ) x/=2LL,f2=true;
if ( !f3 && !(x%3LL) ) x/=3LL,f3=true;
if ( !f2 && !(y%2LL) ) y/=2LL,f2=true;
if ( !f3 && !(y%3LL) ) y/=3LL,f3=true;
if ( !f2 && !(z%2LL) ) z/=2LL,f2=true;
if ( !f3 && !(z%3LL) ) z/=3LL,f3=true;
x%=p;
y%=p;
z%=p;
return x*y%p*z%p;
}
void Push(LL x,LL v)
{
int y=x%M;
while (Hash[y].num) y=(y+1)%M;
Hash[y].num=x;
Hash[y].val=v;
}
LL Dfs(LL x)
{
if (xreturn f[x];
LL temp=Find(x);
if (temp!=-1) return temp;
else temp=Get3(x);
LL last;
for (LL i=2; i<=x; i=last+1)
{
last=x/(x/i);
LL Dec=Dfs(x/i);
Dec=( Get2(last)-Get2(i-1)+p )%p*Dec%p;
temp=(temp-Dec+p)%p;
}
Push(x,temp);
return temp;
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
cin>>p>>n;
Make();
LL last;
for (LL i=1; i<=n; i=last+1)
{
last=n/(n/i);
ans=(ans+ ( Get3(last)-Get3(i-1)+p )%p*Dfs(n/i)%p )%p;
}
cout<return 0;
}