32.hdu6363 因子容斥+模型+数论

版权声明:欢迎转载 https://blog.csdn.net/animalcoder/article/details/82504400

32.hdu6363 因子容斥+组合模型+数论

题意:有N本一摸一样的书,有一个共有K层的书架,现在要把书都放到书架上。

放完后假设第 i层书架有 Bi本书,则该层书架的稳固值为 (2^Bi)-1

定义整个书架的美观值为所有层书架的稳固值的GCD

问现在随机放这些书,整个书架的美观值的期望值是多少。

思路:直接搬得官方题解,很清晰了

所以我们只用考虑GCD(x1,x2,x3….)的贡献

因子容斥,从大的往小容斥的套路。至少因子是g->恰好为g

那个经典组合数是模型

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7;
const int _=1000005;
int fb[_];//斐波那契 
int jc[2*_];//阶乘 
int jv[2*_];//阶乘的逆元 
int qmod(int a,int b)
{
    int res=1;while(b){
        if(b&1)res=1ll*res*a%mod;
        a=1ll*a*a%mod;b=b>>1;
    }
    return res;
}
void init()
{
    fb[0]=0;fb[1]=1;jc[0]=1;jv[0]=1;
    for(int i=2;i<_-2;i++)fb[i]=1ll*(fb[i-1]+fb[i-2])%(mod-1);//扩展欧拉 %(mod-1) 
    for(int i=1;i<2*_;i++)jc[i]=1ll*jc[i-1]*i%mod;
    jv[2*_-1]=qmod(jc[2*_-1],mod-2);
    for(int i=2*_-2;i>=1;i--)jv[i]=1ll*jv[i+1]*(i+1)%mod;   
} 
vector<int>d;int ans[_];
void get(int n)//得N的因子 
{
    for(int i=1;i<=n/i;i++)
        if(n%i==0)
        {
            if(n!=i*i)d.push_back(i),d.push_back(n/i);
            else d.push_back(i);    
        }   
    sort(d.begin(),d.end());
}
int getC(int a,int b){
    return 1ll*jc[a]*jv[b]%mod*jv[a-b]%mod;
}
int main()
{
    init();
    //printf("%d\n",getC(7,3));
    int T;scanf("%d",&T);
    while(T--)
    {
        int n,k;scanf("%d %d",&n,&k);int res=0;
        d.clear();get(n);
        for(int i=0;i<d.size();i++)ans[i]=getC(n/d[i]+k-1,k-1)%mod;
        //枚举gcd为d[i],剩下n/d[i]球个分到k个不同的盒子里,可以空盒 
        
        //至此,ans[i]:gcd至少为i的方案数
        //举个例子N=8,ans[2]=f[2]+f[4]+f[8];ans[4]=f[4]+f[8];ans[8]=f[8]; 
            
        for(int i=d.size()-1;i>=0;i--)
            for(int j=i+1;j<d.size();j++)
                if(d[j]%d[i]==0)ans[i]=1ll*(ans[i]-ans[j]+mod)%mod;
        //因子容斥 ,从大到小搞,算是常见套路! 
                
        //for(int i=0;i<d.size();i++)printf("%d %d %d\n",d[i],ans[i],fb[d[i]]);     
        
        //至此,ans[i]:gcd为i的方案数(从至少到恰有) 
        for(int i=0;i<d.size();i++)
            (res+=1ll*ans[i]*(qmod(2,fb[d[i]])-1)%mod )%=mod;//对每个gcd算贡献 
            
        res=1ll*res*qmod(getC(n+k-1,k-1),mod-2)%mod;//除以总情况,便是期望 
        printf("%d\n",(res+mod)%mod);
    }   
} 

猜你喜欢

转载自blog.csdn.net/animalcoder/article/details/82504400