洛谷3172:选数
题意:
从区间([L,R])选取(N)个整数,总共有((R-L+1)^N)中方案。
问所有方案中,方案中所有数字的(gcd)等于(K)的方案有多少个。
对结果(mod 1e9+7)。
数据范围(1leq N,Kleq10^9,1leq Lleq Rleq10^9,R-lleq 10^5)。
思路:
设(F(n))表示从([L,R])中选(N)个数的(gcd)为(n)或(n)的倍数的情况数。
设(f(n))表示从([L,R])中选(N)个数的(gcd)为(n)的情况数。
很明显有:
[F(n)=sum_{n|d}f(d)
]
莫比乌斯反演:
[f(n)=sum_{n|d}F(d)mu(frac{d}{n})
]
答案是(f(K))。
但是(f(K))不太好求,因为这个倍数其实不是很方便枚举,(f(1))是相对好求的。
所以我们只需要在区间([frac{L}{K},frac{R}{K}])找(f(1))就好了。
但这里有个问题,就是如果(L\%K eq 0),那么就会有(lfloorfrac{L}{K} floor *K<L),会使一些不在([L,R])范围内的数混入答案当中,所以这里加个特判,如果(L\%k eq 0),就有(L=L/K+1)。
接着考虑(F(n))怎么求?
我们知道
[gcd(a,b)=d\
]
有:
[d|a,d|b
]
所以(F(n))就比较好求了,其实就是([L,R])区间范围内,(n)的倍数的个数的(N)次方。
[F(n)=(lfloorfrac{R}{n}
floor-lfloorfrac{L-1}{n}
floor )^N
]
答案就是:
[f(1)=sum_{1|d}F(d)mu(d)\=sum_{d=1}^{R}mu(d)(lfloorfrac{R}{d}
floor-lfloorfrac{L-1}{d}
floor )^N
]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e6;
const int mod = 1e9 + 7;
int primes[maxn+10], cnt;
bool vis[maxn+10];
ll mu[maxn+10];
void init(int n)
{
mu[1] = 1;
for(int i = 2; i <= n; i++)
{
if(!vis[i])
{
primes[++cnt] = i;
mu[i] = -1;
}
for(int j = 1; primes[j] <= n/i; j++)
{
vis[primes[j]*i] = 1;
if(i % primes[j] == 0) break;
else mu[i*primes[j]] = -mu[i];
}
}
for(int i = 1; i <= n; i++)
mu[i] += mu[i-1];
}
ll qmi(ll a, ll b)
{
a %= mod;
ll res = 1; res %= mod;
while(b)
{
if(b&1) res = (res*a)%mod;
a = (a*a)%mod;
b >>= 1;
} return res%mod;
}
unordered_map<ll, ll> Smu;
inline ll getSmu(ll n)
{
if(n <= maxn) return mu[n];
if(Smu[n]) return Smu[n];
ll res = 1;
for(ll l = 2, r; l <= n; l = r+1)
{
r = n/(n/l);
res -= (r-l+1)%mod*getSmu(n/l)%mod;
res = (res%mod+mod)%mod;
} return Smu[n] = res;
}
ll N, K, L, R;
int main()
{
init(maxn);
cin >> N >> K >> L >> R;
R /= K;
if(L % K == 0) L = L/K;
else L = L/K+1;
L = L-1; ll ans = 0;
for(ll l = 1, r; l <= R; l = r+1)
{
if(L/l == 0) r = R/(R/l);
else r = min(R/(R/l), L/(L/l));
ans = (ans+qmi(R/l-L/l, N)%mod*(getSmu(r)-getSmu(l-1))%mod)%mod;
}
cout << (ans%mod+mod)%mod << endl;
return 0;
}