hdu 6363 bookshelf(莫比乌斯反演)

题目:把N本书放到K层的书架上,每一层的美丽值为bi=2*fib[cnt]−1,其中cnt是这一层书的数量,fib[ ]为斐波那契数列,整个书架的美丽值为gcd(b1,b2,...,bk),问整个书架的美丽值的期望。

看了某大佬博客上详细的分析才补上的这个题,写的太好了。

#include
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int MAXN = 1000000;
bool check[MAXN+10];
int prime[MAXN+10],mu[MAXN+10];
void Mobius()
{
    memset(check,false,sizeof(check));
    mu[1] = 1;
    int tot = 0;
    for(int 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 x,ll p)
{
    ll ans=1;
    while(p)
    {
        if(p&1) ans=ans*x%mod;
        x=x*x%mod;
        p>>=1;
    }
    return ans;
}
ll fac[MAXN*2+10],inv[MAXN*2+10],fib[MAXN*2+10];
void init()
{
    fac[0]=1;
    int N=MAXN*2;
    for(int i=1;i<=N;i++)
        fac[i]=fac[i-1]*i%mod;
    inv[N]=qmod(fac[N],mod-2);
    for(int i=N-1;i>=0;i--)
        inv[i]=1ll*(i+1)*inv[i+1]%mod;
    fib[0]=0,fib[1]=1;
    for(int i=2;i<=N;i++)
        fib[i]=(fib[i-1]+fib[i-2])%(mod-1);///fib增长速度超级快,需要利用费马小定理降幂
}
ll C(ll n,ll m)
{
    if(m>n) return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int t,n,k;
int main()
{
    init();
    Mobius();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        ll ans=0;
        for(int i=1;i<=n;i++)
        if(n%i==0)
        {
            ll tmp=0;
            for(int j=i;j<=n;j+=i)
            if(n%j==0)
                tmp=(tmp+mu[j/i]*C(n/j+k-1,k-1)+mod)%mod;
            ans+=tmp*(qmod(2,fib[i])-1)%mod;
            if(ans>mod)
                ans-=mod;
        }
        ans=ans*qmod(C(n+k-1,k-1),mod-2)%mod;
        printf("%I64d\n",ans);
    }
    return 0;
}

下面是普通的容斥代码

#include
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int MAXN = 1000000;
ll qmod(ll x,ll p)
{
    ll ans=1;
    while(p)
    {
        if(p&1) ans=ans*x%mod;
        x=x*x%mod;
        p>>=1;
    }
    return ans;
}
ll fac[MAXN*2+10],inv[MAXN*2+10],fib[MAXN*2+10];
void init()
{
    fac[0]=1;
    int N=MAXN*2;
    for(int i=1;i<=N;i++)
        fac[i]=fac[i-1]*i%mod;
    inv[N]=qmod(fac[N],mod-2);
    for(int i=N-1;i>=0;i--)
        inv[i]=1ll*(i+1)*inv[i+1]%mod;
    fib[0]=0,fib[1]=1;
    for(int i=2;i<=N;i++)
        fib[i]=(fib[i-1]+fib[i-2])%(mod-1);
}
ll C(int n,int m)
{
    if(m>n) return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int t,n,k,p[MAXN+10];
ll ans[MAXN+10];
int main()
{
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        p[0]=0;
        for(int i=1;i<=n;i++)
        if(n%i==0)
            p[++p[0]]=i;
        for(int i=1;i<=p[0];i++)
            ans[i]=C(n/p[i]+k-1,k-1)%mod;
        for(int i=p[0];i>0;i--)
            for(int j=i+1;j<=p[0];j++)
            if(p[j]%p[i]==0)
                ans[i]=(ans[i]-ans[j]+mod)%mod;
        ll res=0;
        for(int i=1;i<=p[0];i++)
            (res+=ans[i]*(qmod(2,fib[p[i]])-1)%mod)%=mod;
        res=res*qmod(C(n+k-1,k-1),mod-2)%mod;
        printf("%I64d\n",res);
    }
    return 0;
}

 

你可能感兴趣的:(多校,数学,莫比乌斯反演)