Description
牛牛是一个热爱算法设计的高中生。在他设计的算法中,常常会使用带小数的数进行计算。牛牛认为,如果在 k
进制下,一个数的小数部分是纯循环的,那么它就是美的。现在,牛牛想知道:对于已知的十进制数 n 和 m,在
kk 进制下,有多少个数值上互不相等的纯循环小数,可以用分数 xy 表示,其中 1≤x≤n,1≤y≤m,且 x,y是整数
。一个数是纯循环的,当且仅当其可以写成以下形式:a.c1˙c2c3…cp-1cp˙其中,a 是一个整数,p≥1;对于 1
≤i≤p,ci是 kk 进制下的一位数字。例如,在十进制下,0.45454545……=0.4˙5˙是纯循环的,它可以用 5/11
、10/22 等分数表示;在十进制下,0.1666666……=0.16˙则不是纯循环的,它可以用 1/6 等分数表示。需要特
别注意的是,我们认为一个整数是纯循环的,因为它的小数部分可以表示成 0 的循环或是 k?1 的循环;而一个小
数部分非 0 的有限小数不是纯循环的。
Input
只有一行,包含三个十进制数N,M,K意义如题所述,保证 1≤n≤10^9,1≤m≤10^9,2≤k≤2000
Output
一行一个整数,表示满足条件的美的数的个数。
Sample Input
2 6 10
Sample Output
4
explanation
满足条件的数分别是:
1/1=1.0000……
1/3=0.3333……
2/1=2.0000……
2/3=0.6666……
1/1 和 2/2 虽然都是纯循环小数,但因为它们相等,因此只计数一次;同样,1/3 和 2/6 也只计数一次。
explanation
满足条件的数分别是:
1/1=1.0000……
1/3=0.3333……
2/1=2.0000……
2/3=0.6666……
1/1 和 2/2 虽然都是纯循环小数,但因为它们相等,因此只计数一次;同样,1/3 和 2/6 也只计数一次。
HINT
Source
神奇的数论
http://www.cnblogs.com/lcf-2000/p/6250330.html
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5000001;
int p[MAXN], tot, f[2002];
long long mu[MAXN], ans;
bool chk[MAXN];
int n, m, K, pk[20], cntk;
map < pair < int, int >, long long > F;
map < int, long long > G;
inline void init()
{
mu[ 1 ] = 1;
for( int i = 2 ; i < MAXN ; i++ )
{
if( !chk[ i ] ) mu[ p[ ++tot ] = i ] = -1;
for( int j = 1 ; i * p[ j ] < MAXN ; j++ )
{
chk[ i * p[ j ] ] = 1;
if( i % p[ j ] ) mu[ i * p[ j ] ] = -mu[ i ];
else break;
}
}
for( int i = 2 ; i < MAXN ; i++ ) mu[ i ] += mu[ i - 1 ];
for( int i = 1 ; i <= K ; i++ ) f[ i ] = f[ i - 1 ] + ( __gcd( i, K ) == 1 );
}
inline int cal(int x) { return x / K * f[ K ] + f[ x % K ]; }
inline long long get(int x)
{
if( x < MAXN ) return mu[ x ];
if( G.find( x ) != G.end() ) return G[ x ];
long long ret = 1;
int pos;
for( int i = 2 ; i <= x ; i = pos + 1 )
{
pos = x / ( x / i );
ret -= ( pos - i + 1 ) * get( x / i );
}
return G[ x ] = ret;
}
inline long long solve(int x, int y)
{
if( !x ) return get( y );
if( y <= 1 ) return y;
if( F.find( make_pair( x, y ) ) != F.end() ) return F[ make_pair( x, y ) ];
return F[ make_pair( x, y ) ] = solve( x - 1, y ) + solve( x, y / pk[ x ] );
}
int main()
{
scanf( "%d%d%d", &n, &m, &K );
init();
int pos;
for( int i = 1 ; p[ i ] <= K ; i++ ) if( K % p[ i ] == 0 ) pk[ ++cntk ] = p[ i ];
for( int i = 1 ; i <= min( n, m ) ; i = pos + 1 )
{
pos = min( n / ( n / i ), m / ( m / i ) );
ans += 1ll * ( solve( cntk, pos ) - solve( cntk, i - 1 ) ) * ( n / i ) * cal( m / i );
}
cout << ans << endl;
return 0;
}