题解 P6788 【「EZEC-3」四月樱花】
P6788 「EZEC-3」四月樱花解题报告:
更好的阅读体验
这是一道比较套路的推柿子题,代码短,可惜我不会做
题意
求
对一质数
数据范围:
分析
考场上看到
可能是求和做多了,一看到求积就蒙了
首先我们有:
所以原式可以转换一下:
然后比较套路地枚举
套路枚举倍数,然后把求积转化为指数上的求和:
注意一下,这里有一个细节,第二个式子的第三个
展开
因为
对
但是还有一个小问题,如何求
我们只需要抵消一下,答案就是
代码
#include<stdio.h>
#define int long long
int i,j,k,m,n,mod,l,r,ans;
int ksm(int a,int b){
b%=(mod-1);
int res=1;
while(b){
if(b&1)
res=res*a%mod;
a=a*a%mod,b>>=1;
}
return res;
}
int calc(int n){
int l=1,r,res=0;
while(l<=n){
r=n/(n/l);
res+=(r-l+1)*(n/l);
l=r+1;
}
return res;
}
signed main(){
scanf("%lld%lld",&n,&mod);
l=1,r=0,ans=1;
while(l<=n){
r=n/(n/l);
ans=(ans*ksm(l*ksm(r+1,mod-2)%mod,calc(n/l))%mod)%mod;
l=r+1;
}
printf("%lld\n",ans*ans%mod);
return 0;
}
更新
然而现在出题人卡掉了上述的算法,现在对上面进行加速。
把上面的式子搬下来:
上面的指数我们还可以化为:
因为
然后掏出杜教筛的式子·
带入进去:
我们需要对后面的式子进行整除分块,所以我们需要筛出
代码
#include<stdio.h>
#include<map>
#define int long long
using namespace std;
const int maxn=5000005;
int i,j,k,m,n,mod,ans,cnt;
int a[maxn],p[maxn],d[maxn],r[maxn],mu[maxn],sumd[maxn],summu[maxn];
map<int,int>ansd,ansmu;
int ksm(int a,int b){//快速幂
b%=(mod-1);//用费马小定理处理一下
int res=1;
while(b){
if(b&1)
res=res*a%mod;
a=a*a%mod,b>>=1;
}
return res;
}
int getmu(int n){//杜教筛筛出莫比乌斯函数
if(n<maxn)
return summu[n];
if(ansmu.count(n))
return ansmu[n];
int l=2,r,res=1;
while(l<=n){
r=n/(n/l);
res-=(r-l+1)*getmu(n/l);
l=r+1;
}
return ansmu[n]=res;
}
int getd(int n){//杜教筛筛出约数函数
if(n<maxn)
return sumd[n];
if(ansd.count(n))
return ansd[n];
int l=2,r,res=n;
while(l<=n){
r=n/(n/l);
res-=(getmu(r)-getmu(l-1))*getd(n/l);
l=r+1;
}
return ansd[n]=res;
}
void init(){//线性筛筛出2/3的前缀和
p[1]=1,d[1]=1,r[1]=1,mu[1]=1;
for(int i=2;i<maxn;i++){
if(p[i]==0)
a[++cnt]=i,d[i]=2,r[i]=1,mu[i]=-1;
for(int j=1;j<=cnt;j++){
if(i*a[j]>=maxn)
break;
p[i*a[j]]=1;
if(i%a[j]==0){
r[i*a[j]]=r[i]+1;
d[i*a[j]]=d[i]/r[i*a[j]]*(r[i*a[j]]+1);
mu[i*a[j]]=0;
break;
}
r[i*a[j]]=1;
d[i*a[j]]=d[i]*2;
mu[i*a[j]]=-mu[i];
}
}
for(int i=1;i<maxn;i++)
sumd[i]=sumd[i-1]+d[i],summu[i]=summu[i-1]+mu[i];
}
int getans(int n){//对答案进行整除分块
int l=1,r=0,res=1;
while(l<=n){
r=n/(n/l);
res=(res*ksm(l*ksm(r+1,mod-2)%mod,getd(n/l))%mod)%mod;
l=r+1;
}
return res;
}
signed main(){
scanf("%lld%lld",&n,&mod);
init();
ans=getans(n);
printf("%lld\n",ans*ans%mod);
return 0;
}