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
記錄G(d)表示在L到H之間選N個數他們的gcd是d的倍數的方案,很顯然答案爲(H/d-(L-1)/d)^N
記錄F(i)表示在L到H之間選N個數他們的gcd恰好是i的方案,那麼G(d)=sigma(F(i)),其中i mod d=0且i不超過H。
通過反演可得F(i)=sigma(mu(d)*G(d/i)),其中d mod i = 0且d不超過H。
另一種是做法:
f[i]表示[L,H]之間選N個不全相同數gcd爲i*k的方案數,根據第一種做法可知gcd爲i*k的倍數的方案數爲(H/(k*i)-(L-1)/(k*i))^N-(區間長度),那麼根據容斥原理我們可以得出只要減去i*k的j倍(其中j大於1)的f[i*j]即可求出。
如果k在[l,r]中,那麼是可以全部相同的。
//注:我並不太理解爲什麼不能把完全相同的一起求。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 100005;
const int MOD = 1000000007;
int f[MAXN], i, j, k, l, r, n;
inline int po(int x, int y)
{
if (!y) return 1;
int tmd = po(x, y >> 1);
tmd = (long long)tmd * tmd % MOD;
if (y & 1) tmd = (long long)x * tmd % MOD;
return tmd;
}
inline void change(int &x)
{
if (x < 0) x += MOD;
}
int main()
{
cin >> n >> k >> l >> r;
int N = r - l + 1;
if (r < l) {cout << 0; return 0;};
for(i = N; i >= 1; i --)
{
int ll = (l - 1) / (k * (long long)i), rr = r / (k * (long long)i);
f[i] = po(rr - ll, n) - (rr - ll); change(f[i]);
for(j = 2; j * i <= N; j ++)
f[i] -= f[j * i], change(f[i]);
}
cout << f[1] + (l <= k && k <= r) << endl;
}