Solution -「NOI 2016」「洛谷 P1587」循环之美
Link.
给定 ,求 ,且最简分数 在 进制下是纯循环小数(包括整数)的 数量。
,。
当你举几个十进制的纯循环小数就不难发现规律了。(
考虑一个已有 的 ,假设它是 进制下的纯循环小数,且循环节长度为 。记 表示 的小数部分值,那么有
所以题目就是要求
略微推一下式子嘛:
套上整除分块,分别研究两个求和,令
快速解决它们,就能整除分块啦。
先考虑 ,显然的事实是 ,继而有
注意到 很小, 预处理之后就能 求 了。
对于 而言, 还能继续莫反——
其中,标注 的步骤同时利用 自身和积性函数普遍的性质进行“无用”转化,巧妙地完成了递推式。直接记忆化计算上式 就可以在可观的复杂度内求出 了,特别地,当 ,需要用杜教筛求 的前缀和。
复杂度据说是 。
/* Clearink */
#include <cmath>
#include <cstdio>
#include <unordered_map>
#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
typedef long long LL;
const int MAXK = 2e3, MAXS = 1e7;
int n, m, K, pn, pr[MAXS + 5];
bool vis[MAXS + 5];
int f[MAXK + 5], mu[MAXS + 5], mus[MAXS + 5];
inline int imin( const int a, const int b ) { return a < b ? a : b; }
inline int gcd( const int a, const int b ) { return b ? gcd( b, a % b ) : a; }
inline LL calcF( const int n ) {
return ( n / K ) * f[K] + f[n % K];
}
inline void sieve() {
mu[1] = mus[1] = 1;
rep ( i, 2, MAXS ) {
if ( !vis[i] ) mu[pr[++pn] = i] = -1;
for ( int j = 1, t; j <= pn && ( t = i * pr[j] ) <= MAXS; ++j ) {
vis[t] = true;
if ( !( i % pr[j] ) ) break;
mu[t] = -mu[i];
}
mus[i] = mu[i] + mus[i - 1];
}
}
inline int calcM( const int n ) {
static std::unordered_map<int, int> mem;
if ( n <= MAXS ) return mus[n];
if ( mem.count( n ) ) return mem[n];
int ret = 1;
for ( int l = 2, r; l <= n; l = r + 1 ) {
r = n / ( n / l );
ret -= ( r - l + 1 ) * calcM( n / l );
}
return mem[n] = ret;
}
inline LL calcS( const int n, const int k ) {
static std::unordered_map<LL, LL> mem;
if ( !n ) return 0;
if ( k == 1 ) return calcM( n );
LL h = n * 2012ll + k;
if ( mem.count( h ) ) return mem[h];
LL ret = 0;
rep ( i, 1, sqrt( 1. * k ) ) if ( !( k % i ) ) {
ret += mu[i] * mu[i] * calcS( n / i, i );
if ( i * i != k ) {
ret += mu[k / i] * mu[k / i] * calcS( n / ( k / i ), k / i );
}
}
return mem[h] = ret;
}
int main() {
// freopen( "cyclic.in", "r", stdin );
// freopen( "cyclic.out", "w", stdout );
scanf( "%d %d %d", &n, &m, &K );
sieve();
rep ( i, 1, K ) f[i] = f[i - 1] + ( gcd( i, K ) == 1 );
LL ans = 0;
for ( int l = 1, r, t = imin( n, m ); l <= t; l = r + 1 ) {
r = imin( n / ( n / l ), m / ( m / l ) );
ans += ( calcS( r, K ) - calcS( l - 1, K ) )
* ( n / l ) * calcF( m / l );
}
printf( "%lld\n", ans );
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现