题解:P10663 BZOJ4833 最小公倍佩尔数
Solution
容易发现
经常学数竞的同学容易发现,上面两个幂的底数都是代数整数,我们很容易整理出一个关于
有一个常用的
对每个质数分开考虑就是
考虑如何刻画
斐波那契数列的递推式和
考虑递推的转移矩阵有
即
则
根据归纳法易得
根据辗转相除法,即得。
一般的,形如
f(n) = k f(n-1) + f(1) ,k \in \mathbb Z 的递推,若f(1) = 1 ,f(2) = k ,则\gcd(f(a),f(b)) = f(\gcd(a,b)) 就成立。
下面开始劲爆莫比乌斯反演。
套用上述公式和莫比乌斯反演的公式易得
考虑
枚举所有使得
复杂度
#include<bits/stdc++.h>
#define int long long
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=1e6+10;
int tc,n,p,pw[MAXN],f[MAXN],inv[MAXN],mu[MAXN],flg[MAXN],cnt[MAXN],g[MAXN];
vector<int> vc;
int qpow(int base,int p,int MOD) {
int ans=1;
while(p) {
if(p&1) ans=ans*base%MOD;
base=base*base%MOD,p>>=1;
}
return ans;
}
void init(int mx) {
mu[1]=1;
ffor(i,2,mx) {
if(!flg[i]) vc.push_back(i),mu[i]=-1;
for(auto v:vc) {
if(i*v>mx) break ;
flg[i*v]=1;
if(i%v==0) break ;
mu[i*v]=-mu[i];
}
}
return ;
}
signed main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
init(1000000);
vc.clear();
ffor(i,1,1000000) if(mu[i]) vc.push_back(i);
cin>>tc;
while(tc--) {
cin>>n>>p;
f[1]=1,f[2]=2;
ffor(i,3,n) f[i]=(2*f[i-1]+f[i-2])%p;
ffor(i,1,n) inv[i]=qpow(f[i],p-2,p);
ffor(i,0,n) g[i]=1;
ffor(d,1,n) {
int lim=n/d;
for(auto id:vc) {
if(id>lim) break ;
int Id=id*d;
if(mu[id]==1) g[Id]=g[Id]*f[d]%p;
else g[Id]=g[Id]*inv[d]%p;
}
}
ffor(i,1,n) g[i]=g[i-1]*g[i]%p;
int ans=0;
ffor(i,1,n) ans=(ans+i*g[i])%p;
cout<<ans<<'\n';
}
return 0;
}
本题完整的输入,可以用来调试:Link