[CQOI2015]選數
Description
Input
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;
}