bzoj3930

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;
}



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