HDU 6363 bookshelf(数论+莫比乌斯反演)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/V5ZSQ/article/details/82562792

Description

n 本书等概率随机放在 k 层书架上,如果第 i 层书架上有 c n t i 本书,那么该层书架的稳定值为 s t a b l e i = f [ c n t i ] ,其中 f [ 0 ] = 0 , f [ 1 ] = 1 , f [ i ] = f [ i 1 ] + f [ i 2 ] 为斐波那契数列,美观度为 b e a u t y i = 2 s t a b l e i 1 ,此时得分为 g c d ( b e a u t y 1 , . . . , b e a u t y k ) ,求得分期望值

Input

第一行一整数 T 表示用例组数,每组用例输入两个整数 n , k ( 1 T 10 , 0 < n , k 10 6 )

Output

输出得分期望值,结果模 10 9 + 7

Sample Input

1
6 8

Sample Output

797202805

Solution

首先证明两个结论:

1. g c d ( 2 a 1 , 2 b 1 ) = 2 g c d ( a , b ) 1

假设 a b ,则有
$$
\begin{array}{rcl}
gcd(2^a-1,2^b-1)&=&gcd(2^{a-b}(2^b-1)+2^{a-b}-1,2^b-1)\
&=&gcd(2^{a-b}-1,2^b-1)\

&…&\
&=&gcd(2^{a\%b}-1,2^b-1)
\end{array}
$$
辗转相除即得结论.

2. g c d ( f a , f b ) = f g c d ( a , b )

首先注意到

g c d ( f x , f x 1 ) = g c d ( f x 1 + f x 2 , f x 1 ) = g c d ( f x 1 , f x 2 ) = . . . = g c d ( f 1 , f 2 ) = 1

假设 a b ,那么有
f x = f x 1 + f x 2 = 2 f x 2 + f x 3 = . . . = f y + 1 f x y + f y f x y 1

则有
g c d ( f x , f y ) = g c d ( f y + 1 f x y + f y f x y 1 , f y ) = g c d ( f y + 1 f x y , f y ) = g c d ( f x y , f y ) . . . = g c d ( f x % y , f y )

辗转相除即得结论.

现在考虑原问题,由上面两个结论即得到当 k 个书架上书的数量为 a 1 , . . . , a k 时,其得分即为 2 f g c d ( a 1 , . . . , a k ) 1 ,总方案数即为将 n 本书放入 k 个书架,方案数 C n + k 1 k 1 ,假设 g c d ( a 1 , . . . , a k ) = d , a 1 + . . . + a k = n 的方案数有 g ( d ) 种,那么答案即为 a n s = d | n g ( d ) ( 2 f d 1 ) ,故只要求出 g ( 1 ) , . . . , g ( d ) 即可

d | g c d ( a 1 , . . . , a k ) , a 1 + . . . + a k = n 的方案数为 F ( d ) ,由插板法知 F ( d ) = C n d + k 1 k 1

F ( d ) = d | i g ( i ) ,由莫比乌斯反演有 g ( d ) = d | i μ ( i d ) F ( i ) ,预处理莫比乌斯函数后直接求解即可

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 1000005
typedef long long ll;
int prime[maxn],mu[maxn],check[maxn],tot;
void Moblus(int n=1e6)
{
    memset(check,0,sizeof(check));
    mu[1]=1;
    tot=0;
    for(int i=2;i<=n;i++)
    {
        if(!check[i])
        {
            prime[tot++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<tot&&i*prime[j]<=n;j++)
        {           
            check[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
    }
}
#define mod 1000000007
int mul(int x,int y)
{
    ll z=1ll*x*y;
    return z-z/mod*mod;
}
int add(int x,int y)
{
    x+=y;
    if(x>=mod)x-=mod;
    return x;
}
int Pow(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)ans=mul(ans,a);
        a=mul(a,a);
        b>>=1;
    }
    return ans;
}
int a[maxn],fact[2*maxn],inv[2*maxn];
void init(int n=1e6)
{
    Moblus();
    a[0]=0,a[1]=1;
    for(int i=2;i<=1e6;i++)a[i]=(a[i-2]+a[i-1])%(mod-1);
    for(int i=1;i<=1e6;i++)a[i]=add(Pow(2,a[i]),mod-1);
    fact[0]=1;
    for(int i=1;i<=2*n;i++)fact[i]=mul(i,fact[i-1]);
    inv[1]=1;
    for(int i=2;i<=2*n;i++)inv[i]=mul(mod-mod/i,inv[mod%i]);
    inv[0]=1;
    for(int i=1;i<=2*n;i++)inv[i]=mul(inv[i],inv[i-1]);
}
int C(int n,int m)
{
    if(m<0||m>n)return 0;
    return mul(fact[n],mul(inv[m],inv[n-m]));
}
int F(int d,int k)
{
    return C(d+k-1,k-1);
}
int main()
{
    init();
    int T,n,k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        int ans=0;
        for(int d=1;d<=n;d++)
            if(n%d==0)
            {
                int f=0;
                for(int i=d;i<=n;i+=d)
                    if(n%i==0)
                    {
                        if(mu[i/d]==1)f=add(f,F(n/i,k));
                        else if(mu[i/d]==-1)f=add(f,mod-F(n/i,k));
                    }
                ans=add(ans,mul(f,a[d]));
            }
        printf("%d\n",mul(ans,Pow(C(n+k-1,k-1),mod-2)));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/V5ZSQ/article/details/82562792
今日推荐