bzoj3930

来源:互联网 发布:小海家淘宝 编辑:程序博客网 时间:2024/06/05 10:05

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



0 0
原创粉丝点击