版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yz467796454/article/details/81673051
题目链接:hdu 6363 bookshelf
Sample Input
1
6 8
Sample Output
797202805
题意:n本书放到k层书架上,放完后,若某一层有x本书,则这一层的稳固值f(x),f是斐波那契数列,美观值为,整个书架的美观值为所有层的美观值的gcd,求书架美观值的期望值。
思路:太难了!直接贴题解
这个gcd的性质是数论中有的,不会证明,凑合看吧
莫比乌斯反演学习了一下,实在不会,可以看这篇博客:bookshelf HDU - 6363(数论结论+莫比乌斯反演)
关于莫比乌斯反演可以看这个博客:莫比乌斯反演详解
我的代码是用了下面的方法,可以参照这个博客的解释:HDU-6363:bookshelf(数论+容斥)
至于欧拉降幂我没有用到,欧拉降幂是说
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
#define maxn 2000006
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll b[maxn],inv[maxn],invf[maxn];
ll f[maxn];
int num[maxn];
ll sum[maxn];
ll mo(ll a,ll pp){
if(a>=0&&a<pp)return a;
a%=pp;
if(a<0)a+=pp;
return a;
}
ll mo(ll a){
if(a>=0&&a<mod)return a;
a%=mod;
if(a<0)a+=mod;
return a;
}
ll powmod(ll a,ll b,ll pp){
ll ans=1;
for(;b;b>>=1,a=mo(a*a,pp)){
if(b&1)ans=mo(ans*a,pp);
}
return ans;
}
ll powmod(ll a,ll b){
ll ans=1;
for(;b;b>>=1,a=mo(a*a)){
if(b&1)ans=mo(ans*a);
}
return ans;
}
ll C(int n,int m){
if(n<m)return 0;
if(m==n||m==0)return 1;
return b[n]*invf[n-m]%mod*invf[m]%mod;
}
void init(){
b[0]=1;
for(int i=1;i<maxn;i++)b[i]=b[i-1]*i%mod;
//for(int i=0;i<maxn;i++)inv[i]=powmod(b[i],mod-2,mod);这样求会TLE
inv[1]=1;//逆元
for(int i=2;i<maxn;i++)inv[i]=((mod-mod/i)*inv[mod%i])%mod;
invf[0]=1;//累乘逆元
for(int i=1;i<maxn;i++)invf[i]=(invf[i-1]*inv[i])%mod;
f[0]=0;f[1]=1;f[2]=1;
for(int i=3;i<maxn;i++)f[i]=(f[i-1]+f[i-2])%(mod-1);
}
ll inv1(ll b){
return powmod(b,mod-2,mod);
}
ll inv2(ll a){
if(a==1)return 1;
return inv2(mod%a)*inv2(mod-mod/a)%mod;
}
int main(){
int t;
scanf("%d",&t);
init();
while(t--){
int n,k;
scanf("%d%d",&n,&k);
int cnt=0;
for(int i=1;i<=n;i++){
if(n%i==0)num[cnt++]=i;//num存n的因子
}
for(int i=0;i<cnt;i++){// 系数和为n/g的方案数
sum[i]=C(n/num[i]+k-1,k-1);
}
for(int i=cnt-2;i>=0;i--){//把是g的倍数但不是g的方案数去掉
for(int j=i+1;j<cnt;j++){
if(num[j]%num[i]==0){
sum[i]=(sum[i]-sum[j]+mod)%mod;
}
}
}
ll ans=0;
for(int i=0;i<cnt;i++){
ans=(ans+(powmod(2,f[num[i]])-1+mod)%mod*sum[i]%mod)%mod;
}
printf("%lld\n",ans*inv1(C(n+k-1,k-1))%mod);
}
return 0;
}