数学题 我不会 我不会
莫比乌斯反演 啥玩意 嘤嘤嘤
题意:
把n本书放到k层的书架上,每一层的美丽值为bi=2^f[cnt]−1,其中cnt是这一层书的数量,f[x]为斐波那契数列,整个书架的美丽值为gcd(b1,b2,...,bk),问整个书架的美丽值的期望
思路: 什么数论结论 简单可得 我怎么什么都不知道
如何求f(g) 一开始的想法是 将n本书 每g本为一组 那么n本书分组后 就有 n/g组 然后用隔板法
k个书架可以用 k-1个隔板 分出 那么总共的位置就有 n/g+k-1个
那么分法的个数就是组合数 但仔细一想会发现 里面包括了gcd是g的倍数的所有情况
那么现在令F(g)为gcd是g的倍数的所有情况 即F(g)=
我们可以发现F(g)=f(g)+f(2g)+f(3g)+.... = f(y);
接下来我们就要了解莫比乌斯反演这玩意
证明 面向csdn吧 这时就能发现 上述的公式满足倍数的莫比乌斯反演
那么我们只要枚举每个gcd 然后枚举每个gcd的所有倍数 就能算出答案 那么u怎么求 套莫比乌斯的板子吧
代码:
#include
using namespace std;
typedef long long LL;
const int maxn = 1e6 + 5;
const LL mod = 1e9 + 7;
const LL mm = 1e9 + 6;
LL inv[maxn * 2 + 5],fac[maxn * 2 + 5];
bool check[maxn];
LL prime[maxn],mu[maxn],f[maxn],n,k;
LL exgcd(LL a,LL b,LL& x,LL& y){
if(a == 0 && b == 0) return -1;
if(b == 0){
x = 1,y = 0;
return a;
}
LL d = exgcd(b,a % b,y,x);
y -= a / b * x;
return d;
}
//求逆元
LL rev(LL a,LL n){
LL x,y;
LL d = exgcd(a,n,x,y);
return (x % n + n) % n;
}
void init_inv(){
fac[0] = 1;
//预处理阶乘
for(LL i = 1;i < 2 * maxn;++i) fac[i] = fac[i - 1] * i % mod;
//预处理阶乘的逆元
inv[2 * maxn - 1] = rev(fac[2 * maxn - 1],mod);
for(LL i = 2 * maxn - 2;i >= 0;--i){
inv[i] = (i + 1) * inv[i + 1] % mod;
}
}
//求组合数
LL C(LL a,LL b){
LL m = a,n = b;
return ((fac[n] * inv[m]) % mod * inv[n - m]) % mod;
}
void init(){
f[0] = 0,f[1] = 1;
for(int i = 2;i < maxn;++i){
f[i] = (f[i - 1] + f[i - 2]) % mm;
}
}
// 莫比乌斯反演求 u函数
void mobius(){
memset(check,false,sizeof(check));
mu[1] = 1;
int tot = 0;
for(LL i = 2;i < maxn;++i){
if(!check[i]){
prime[tot++] = i;
mu[i] = -1;
}
for(int j = 0;j < tot;++j){
if(i * prime[j] > maxn) break;
check[i * prime[j]] = true;
if(i % prime[j] == 0){
mu[i * prime[j]] = 0;
break;
}
else mu[i * prime[j]] = -mu[i];
}
}
}
LL qmod(LL a,LL n){
LL ret = 1;
while(n){
if(n & 1) ret = ret * a % mod;
a = a * a % mod;
n = n>>1;
}
return ret;
}
int main(){
init_inv();
mobius();
init();
int T;
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&n,&k);
LL denominator = C(k-1,n + k - 1);
denominator = rev(denominator,mod);
LL ans = 0;
//枚举每个gcd
for(int i = 1;i <= n;++i){
if(n % i) continue;
LL div = i;
LL contri = (qmod(2,f[div]) - 1 + mod) % mod;
LL cnt = 0;
//枚举每个gcd的倍数
for(LL j = div;j <= n;j += div){
if(n % j) continue;
LL d = j;
cnt += mu[d / i] * C(k-1,n / d + k - 1) % mod;
cnt = (cnt % mod + mod) % mod;
}
ans += contri * cnt % mod;
ans %= mod;
}
ans = ans * denominator % mod;
printf("%lld\n",ans);
}
return 0;
}