BZOJ4652: [Noi2016]循环之美

来源:互联网 发布:日剧 商务 知乎 编辑:程序博客网 时间:2024/05/16 04:32

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 也只计数一次。

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


0 0
原创粉丝点击