「CQOI2015」選數
求在區間
我們發現如果要使選出的數的最大公約數爲
再觀察一下,我們會發現這些
所以我們設
那麼
我們要求的就是
我們發現,當
所以我們可以在
要注意取模的數作差的時候要加上模數!
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1000000007;
const int N = 5000000;
const int LIM = 1000000;
ll ksm( ll a, int b )
{
ll ret = 1;
while( b )
{
if( b & 1 ) ret = (ret * a) %MOD;
a = (a * a) %MOD; b >>= 1;
}
return ret;
}
map <int, ll> m;
bool is_prime[N];
int tot = 0, prime[N], mobius[N];
int n, k, L, R;
void init( int size )
{
memset( is_prime, true, sizeof( is_prime ) );
is_prime[1] = 1; mobius[1] = 1;
for( int i = 2; i <= size; i ++ )
{
if( is_prime[i] )
prime[++tot] = i, mobius[i] = -1;
for( int j = 1; j <= tot; j ++ )
{
int k = i * prime[j];
if( k > size ) break;
is_prime[k] = false;
if( i % prime[j] == 0 )
mobius[k] = 0;
else mobius[k] = - mobius[i];
}
}
for( int i = 2; i <= size; i ++ )
mobius[i] = (mobius[i] + mobius[i-1]) %MOD;
}
ll calc_mobius( int x )
{
if( x <= LIM ) return mobius[x];
if( m[x] ) return m[x];
int next = 0; ll ret = 0;
for( int i = 2; i <= x; i = next + 1 )
{
next = x / ( x / i );
ret -= calc_mobius(x/i) * (next-i+1);
}
m[x] = ret %MOD;
return ret %MOD;
}
int main()
{
init( LIM );
scanf( "%d%d%d%d", &n, &k, &L, &R );
R = R / k; L = ( L - 1 ) / k;
int next = 0; ll ans = 0;
for( int i = 1; i <= R; i = next + 1 )
{
// printf( "i:%d, L:%d, R:%d\n", i, L, R );
if( L/i ) next = min( R/(R/i), L/(L/i) ); else next = R / (R/i);
ans += ( ksm( (R/i)-(L/i), n ) * ( calc_mobius(next) - calc_mobius(i-1) + MOD ) %MOD);
ans %= MOD;
// printf( "next:%d, mobsum(next):%d\n", next, calc_mobius(next) );
}
printf( "%lld\n", ans );
return 0;
}
// 2 2 2 4