列表

详情


NC17897. [NOI2016]循环之美

描述

牛牛是一个热爱算法设计的高中生。在他设计的算法中,常常会使用带小数的数进行计算。牛牛认为,如果在k进制下,一个数的小数部分是纯循环的,那么它就是美的。现在,牛牛想知道:对于已知的十进制数n和m,在k进制下,有多少个数值上互不相等的纯循环小数,可以用分数 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 的有限小数不是纯循环的

输入描述

只有一行,包含三个十进制数N,M,K意义如题所述,保证 1≤n≤10^9,1≤m≤10^9,2≤k≤2000

输出描述

一行一个整数,表示满足条件的美的数的个数。

示例1

输入:

2 6 10

输出:

4

说明:

满足条件的数分别是:
1/1=1.0000……
1/3=0.3333……
2/1=2.0000……
2/3=0.6666……
1/1 和 2/2 虽然都是纯循环小数,但因为它们相等,因此只计数一次;同样,1/3 和 2/6 也只计数一次。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++11) 解法, 执行用时: 445ms, 内存消耗: 66912K, 提交时间: 2021-04-30 20:19:45

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

上一题