1. 程式人生 > >洛谷 [CQOI2015]選數 解題報告

洛谷 [CQOI2015]選數 解題報告

[CQOI2015]選數

題目描述

我們知道,從區間\([L,H]\)\(L\)\(H\)為整數)中選取\(N\)個整數,總共有\((H-L+1)^N\)種方案。

\(z\)很好奇這樣選出的數的最大公約數的規律,他決定對每種方案選出的\(N\)個整數都求一次最大公約數,以便進一步研究。然而他很快發現工作量太大了,於是向你尋求幫助。

你的任務很簡單,小\(z\)會告訴你一個整數\(K\),你需要回答他最大公約數剛好為\(K\)的選取方案有多少個。由於方案數較大,你只需要輸出其除以\(1000000007\)的餘數即可。

輸入輸出格式

輸入格式:

輸入一行,包含\(4\)個空格分開的正整數,依次為\(N\)

\(K\)\(L\)\(H\)

輸出格式:

輸出一個整數,為所求方案數。

說明

對於\(100\%\)的資料,\(1 \le N, K \le 10^9\)\(1 \le L \le H \le 10^9\)\(H-L \le10^5\)


暴力反演一波你會發現要求這個式子

\[\sum_{d=1}^{\lfloor\frac{r}{k}\rfloor}\mu(d)(\lfloor\frac{\lfloor\frac{r}{k}\rfloor}{d}\rfloor-\lfloor\frac{\lceil\frac{l}{k}\rceil-1}{d}\rfloor)\]

需要使用杜教篩,不想學,發現還有一個神仙的\(DP\)

\(r=\lfloor\frac{r}{k}\rfloor,l=\lceil\frac{l}{k}\rceil\)

問題等價於問互質的方案數

引理:區間\([l,r]\)任意兩個不相等數的最大公約數的大小不會超過\(r-l\)

證明:取任意互質的數\(a,b\),將它們同乘\(m\),而\(r-l\)取最小值時\((b-a)\times m \ge m\),得證

(證明是從別處抄的,說實話不太懂QAQ)

\(dp_{i}\)代表以\(i\)為最大公約數的數量,且所選的數不全相等。

考慮\(g_i\)\(i\)為約數的數量,同樣也是所選的不全相等。

(不全相等是處於統計方便考慮)

顯然

\[g_i=(\lfloor\frac{r}{i}\rfloor-\lfloor\frac{l-1}{i}\rfloor)^n-(\lfloor\frac{r}{i}\rfloor-\lfloor\frac{l-1}{i}\rfloor)\]

根據容斥原理

\[dp_i=g_i-\sum_{i|d}^rdp_d\]

注意要特判\(l=1\),因為這個時候可以全相等


Code:

#include <cstdio>
#define ll long long
const int N=1e5+10;
const ll mod=1e9+7;
ll n,k,l,r;
ll dp[N];
ll quickpow(ll d,ll k)
{
    ll f=1;
    while(k)
    {
        if(k&1) f=f*d%mod;
        d=d*d%mod;
        k>>=1;
    }
    return f;
}
int main()
{
    scanf("%lld%lld%lld%lld",&n,&k,&l,&r);
    l=(l-1)/k+1,r=r/k;
    for(ll i=1;i<=r-l;i++)
    {
        ll cnt=(r/i-(l-1)/i);
        dp[i]=quickpow(cnt,n)-cnt;
    }
    for(ll i=r-l;i;i--)
        for(ll j=i<<1;j<=r-l;j+=i)
            (dp[i]-=dp[j])%=mod;
    printf("%lld\n",(dp[1]+(l==1)+mod)%mod);
    return 0;
}

2018.10.20