bookshelf(斐波那契gcd,容斥因子,欧拉降幂)

本文解析了HDU6363题目的求解思路,涉及将n本书分配到k个书架上的问题,并求解各书架价值最大公约数的期望。通过分析斐波那契数列特性及应用容斥原理进行高效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题 : hdu 6363

题意 :

n本书塞进k个书架,第i层的书为x,那么第i层的价值 vi v i 2F(x)1(F(x)) 2 F ( x ) − 1 ( F ( x ) 为 斐 波 那 契 数 列 ) ,求 gcd(v1...vk) g c d ( v 1 . . . v k ) 的期望 (gcd(0,x)=x) ( g c d ( 0 , x ) = x )

解析 :

对于任意两个书架的书的数量a,b

gcd(2F(a)1,2F(b)1)2gcd(F(a),F(b))12F(gcd(a,b))1 g c d ( 2 F ( a ) − 1 , 2 F ( b ) − 1 ) ⇒ 2 g c d ( F ( a ) , F ( b ) ) − 1 ⇒ 2 F ( g c d ( a , b ) ) − 1

对于n的任意分割情况 n=x1+x2+...+xk:ans=gcd(v1...vk),d=gcd(x1,x2...xk) n = x 1 + x 2 + . . . + x k 设 : a n s = g c d ( v 1 . . . v k ) , d = g c d ( x 1 , x 2... x k )

ans=2F(d)1 a n s = 2 F ( d ) − 1

那么我们可以遍历所有的可能的d,并得出d所对应的出现次数

这个做法和前几天做的欧拉函数的题差不多,对n的因数容斥一下就好

容斥:

对于一个n的因数x,d(上述)为x的倍数的方案数为 Ck+1n/x+k+1 C n / x + k + 1 k + 1 (看成n/x个x块,中间插k-1个板子分成k个部分(0也合法),方案数为全排列除去板子的顺序和块的顺序)

当然,这种方法把d=x,2x,ix都包括进来了,所以从上往下维护去重便是d=x的次数了

考虑到 2F(d) 2 F ( d ) 要炸,需要用欧拉降幂处理

ap,ab%p=ab%ϕ(p)%p a 和 p 互 质 的 情 况 下 , a b % p = a b % ϕ ( p ) % p
ap,ab%p=ab%phi(p)+phi(p)%p a 和 p 不 互 质 的 情 况 下 , a b % p = a b % p h i ( p ) + p h i ( p ) % p

最终答案为:

d|n((2F(d)1)g(d))Ck1n+k1(g(d)d) ∑ d | n ( ( 2 F ( d ) − 1 ) ∗ g ( d ) ) C n + k − 1 k − 1 ( g ( d ) 为 d 的 次 数 )



代码:


#include<bits/stdc++.h>
#define debug(ii) printf("-> %lld\n",ii)
#define mmm(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int N=2000000;//C(n+k-1,k-1)所以开两倍
const ll mod =1e9+7;

ll swift(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1ll)ans=ans*a%mod;
        b>>=1;a=a*a%mod;
    }
    return ans;
}

ll g[N+9],fac[N+9],inv_fac[N+9],f[N+9];

ll C(ll a,ll b){
    if(b>a||b<0||a<0)return 0;
    return fac[a]*inv_fac[b]%mod*inv_fac[a-b]%mod;
}

void init(){
    fac[1]=fac[0]=1;
    for(ll i=2;i<=N;i++)
        fac[i]=fac[i-1]*i%mod;

    inv_fac[N]=swift(fac[N],mod-2);
    for(ll i=N-1;i>=0;i--)
        inv_fac[i]=inv_fac[i+1]*(i+1ll)%mod;

    f[0]=0,f[1]=1;
    for(int i=2;i<=N;i++)
        f[i]=(f[i-1]+f[i-2])%(mod-1);//欧拉降幂
}

ll vd[N+9],tot;

int main(){
    init();
    int t;scanf("%d",&t);
    while(t--){
        mmm(g,0);tot=0;
        ll n,k;scanf("%lld%lld",&n,&k);
        for(ll i=1;i<=n;i++)if(n%i==0)vd[++tot]=i;

        for(int i=tot;i>0;i--){
            ll d=vd[i];
            g[d]=C(n/d+k-1,k-1);
            for(int j=i+1;j<=tot;j++)
                if(vd[j]%d==0)
                g[d]=(g[d]-g[vd[j]]+mod)%mod;
        }

        ll ans=0;
        for(int i=1;i<=tot;i++){
            ll d=vd[i];
            ans=(ans+(swift(2,f[d])-1)%mod*g[d]%mod)%mod;
        }

        ans=ans*swift(C(n+k-1,k-1),mod-2)%mod;
        printf("%lld\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值