先吐槽一下:唐老師下標全崩了,最重要的後面的一坨推導全都掛了qwq,我推到倒數第二步然後和題解一對發現我好想全推錯了233333? 最後還是找的A了的zyz才弄明白他寫的是什麼
這題和一道斐波那契公倍數比較像,先說這個吧
先考慮給你的那個式子,你上面減下面再移個項就變成通項公式了
然後通過特徵根/觀察/打表你get了這個遞推式是
觀察這個遞推式的性質,首先我們能夠得到
然後考慮
然後我們get了一個非常關鍵的結論是
證明的話考慮一種讓
此時
前面那項顯然可以直接去掉了,因爲是
那麼剩下的是
注意到
所以他等於
現在可以考慮
考慮
然後我們子集反演一下就得到了
注意到
一個經典思路考慮構造數列
把這個帶進去就有
考慮直接枚舉一個
這個是怎麼來的呢?考慮這樣一個事情,對於一個元素來說他被選擇而且是
所以一個元素總的貢獻就是
但是注意到前面是符號所以是減去這個貢獻還有空集,空集的貢獻就是1,所以就有了上面的那個式子了
然後考慮後面那個東西在
那麼
通過廣義莫比烏斯反演我們可以知道他等於同等運算在mu意義下的逆運算
問題完美解決,時間複雜度
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6+5;
int prime[N], cnt, mu[N];
bool F[N];
typedef long long LL;
inline int pow(int a,int b,int mod) {
LL res = 1;
for(;b;b>>=1,a=(LL)a*a%mod)
if(b&1)
res = res * a % mod;
return res;
}
inline void init() {
const int Max = 1e6;
mu[1] = 1;
for(int i=2;i<=Max;++i) {
if(!F[i]) mu[i] = -1, prime[++cnt] = i;
for(int j=1;prime[j]*i<=Max;++j) {
F[i*prime[j]] = 1;
if(i%prime[j]==0) break;
mu[i*prime[j]] = -mu[i];
}
}
}
int f[N], h[N], g[N], inv[N];
int main() {
int T;
cin >> T;
init();
while(T--) {
int Max, mod;
cin >> Max >> mod;
f[1] = 1, f[2] = 2;
register int i; int x;
for(i=3;i<=Max;++i) f[i] = (2ll * f[i-1] + f[i-2]) % mod;
for(i=1;i<=Max;++i) h[i] = 1;
for(i=1;i<=Max;++i) inv[i] = pow(f[i], mod-2,mod);
for(int d=1;d<=Max;++d) {
for(i=1;i*d<=Max;++i) {
x = i * d;
if(mu[i] == 1)
h[x] = (LL) h[x] * f[d] % mod;
else if(mu[i] == -1)
h[x] = (LL) h[x] * inv[d] % mod;
}
}
for(i=2;i<=Max;++i) h[i] = (LL) h[i] * h[i-1] % mod;
for(i=1;i<=Max;++i) g[i] = h[i];
LL ans = 0;
for(i=1;i<=Max;++i) ans = (ans + (LL) g[i] * i % mod) % mod;
cout << ans << endl;
}
}