Luogu P3172 [CQOI2015]選數

[CQOI2015]選數

Description

我們知道,從區間[L,H](L和H爲整數)中選取N個整數,總共有(H-L+1)^N種方案。小z很好奇這樣選出的數的最大公約數的規律,他決定對每種方案選出的N個整數都求一次最大公約數,以便進一步研究。然而他很快發現工作量太大了,於是向你尋求幫助。你的任務很簡單,小z會告訴你一個整數K,你需要回答他最大公約數剛好爲K的選取方案有多少個。由於方案數較大,你只需要輸出其除以1000000007的餘數即可

Input

輸入一行,包含4個空格分開的正整數,依次爲N,K,L和H

Output

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

Sample Input

2 2 2 4

Sample Output

3

Answer

我們把左右區間分別處理:    r = r / k;    l = (l - 1) / k + 1;

這樣問題就轉化爲求[l,r]區間內,選n個數其最大公約數爲1的方案數

因爲r-l<=105 所以這個區間內任意兩個不相等的數的最大公約數最大不超過(r - l) <= 105 證明很好證:因爲兩個數p > q的最大公約數如果爲x,那麼p / x - q / x >= 1,那麼p - q >= x、、、、、、

所以可以暴力所有的最大公約數,設[l,r]中選n個不完全相同的數其最大公約數爲i的方案數爲dp[i]

那麼[l,r]中有多少含i因子的數呢?

顯然有t = r / i - (l - 1) / i個數

那麼dp[i] = tn 種方案,但是這裏面肯定有n個數都相同的方案一共有t個,所以dp[i] = (tn - t) % mod;種方案

但是這個時候是所有n個數有i因子的方案數,而不是gcd=i的方案數,所以dp[i] = dp[i] - dp[j](j <= r - l && j | i)

然後這樣dp[1]就是正解了

但是我們注意到,我們的dp[1]是在[l,r]中選n個不完全相同的數其最大公約數爲i的方案數,但是實際上我們可以讓n個數完全相同(假設爲x),但是這樣的話n個數的gcd就等於x,所以x必須爲k,因爲求的是gcd=k的方案數

所以當k∈[l,r]時,dp[1] = dp[1] + 1;

代碼如下:

#include 
#define maxn (100000 + 10)
typedef long long int LLI;
using namespace std;
int dp[maxn];
int p = 1000000007;

LLI Fast_power(LLI n,LLI k,LLI mod) {
    LLI re = 1;
    n = n % mod;
    while(k) {
        if(k & 1)   re = re * n % mod;
        k = k >> 1;
        n = n * n % mod;
    }
    return re;
}

int main() {
//    freopen("in.txt","r",stdin);
    int l,r,n,k;
    bool flag = false;
    scanf("%d%d%d%d",&n,&k,&l,&r);
    if(k >= l && k <= r)    flag = true;
    r = r / k;
    l = (l - 1) / k;
    for(int i = r - l; i >= 1; i --) {
        int t = r / i - l / i;
        dp[i] = (Fast_power(t,n,p) - t + p) % p;
        for(int j = 2; j * i <= r - l; j ++)
            dp[i] = (dp[i] - dp[i * j] + p) % p;
    }
    if(flag == true)    dp[1] ++;
    printf("%d\n",dp[1] % p);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章