题目
思路
其实非常直观,要通过若干次跳跃跳到当前格减1的格子,根据裴蜀定理,只需要:
那么最终答案就是:
其中σ(n)表示n的所有因数之和。
众所周知这题的标签是莫比乌斯反演(当时我还在苦恼呢),函数可以用莫比乌斯反演处理,有:
那么考虑把它带进去,可以变换枚举顺序,把d提到前面,得:
代码
因为只有一个∑,那就不搞麻烦的预处理了:考虑直接枚举n的质因数d,并写一个dfs把n所有的因数枚举出来:
//d:处理后m的质因数
x=m;
for(int i=2;i*i<=x;i++)
{
if(x%i==0)
{
d[++nd]=i;
while(x%i==0)x/=i;
}
}
if(x>1)d[++nd]=x;
dfs过程中可以顺便处理莫比乌斯函数——这样就可以不写预处理了:
void dfs(ll id,ll val,ll mu)
//d:处理后m的质因数
//id:处理后质因数下标
//val:当前因数值
//mu:欧拉函数值
{
if(id==nd+1)
{
ans+=mu*qpow(m/val,n);
//qpow函数:快速幂
return;
}
dfs(id+1,val,mu);
dfs(id+1,val*d[id],-mu);
}
总体代码贴贴:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=4e6+9;
ll n,m,x;
ll ans,d[N],nd;
ll qpow(ll x,ll k)
{
ll res=1;
while(k)
{
if(k&1)res=res*x;
x=x*x;
k>>=1;
}
return res;
}
void dfs(ll id,ll val,ll mu)
{
if(id==nd+1)
{
ans+=mu*qpow(m/val,n);
return;
}
dfs(id+1,val,mu);
dfs(id+1,val*d[id],-mu);
}
int main()
{
scanf("%lld%lld",&n,&m);
x=m;
for(int i=2;i*i<=x;i++)
{
if(x%i==0)
{
d[++nd]=i;
while(x%i==0)x/=i;
}
}
if(x>1)d[++nd]=x;
dfs(1,1,1);
printf("%lld",ans);
return 0;
}