Address
https://www.lydsy.com/JudgeOnline/problem.php?id=4652
http://uoj.ac/problem/221
Solution……
一、
我们知道,
进制小数
(循环节为
个
和
个
)等于
。
于是,乱搞一下,
时
纯循环当且仅当存在一个
满足
。
于是:
如果 则易得上面的方程无解。否则根据欧拉定理,一个合法解是 。
于是,我们要求的答案为:
二、反演
上式
对 下界分块即可。
可以考虑求:
使得该式变为:
由于 的取值只有 种, 的取值只有 种,故可对 下界分块,需要求出 的前缀和:
三、解决掉
我们知道,
。
于是:
预处理出 表示 中与 互质的数的个数之后,就可以 求 。
四、解决掉
考虑再反演一次:
众所周知, 是个积性函数,且有:
故:
我们得到 的递推式,可用记忆化搜索求得。
特别地,由于任意都与 互质,故 。故当 时杜教筛即可。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Edge(u) for (int e = adj[u]; e; e = nxt[e])
#define For(i, a, b) for (i = a; i <= b; i++)
#define Step(i, a, b, x) for (i = a; i <= b; i += x)
#define Mobius(i, a, b) for (i = a; i <= b;)
using namespace std;
typedef long long ll;
const int MaxN = 1e6, N = MaxN + 5, MaxM = 2000, M = MaxM + 5, E = 41,
ZZQ = 19260817, L = 2e7 + 5, INF = 0x3f3f3f3f;
int n, m, k, tot, pri[N], miu[N], sum[N], divis[M][M], ums[M],
ecnt, nxt[L], adj[ZZQ], gon[L], gok[L], val[L];
bool mark[N];
ll ans;
template <class T>
T Min(T a, T b) {return a < b ? a : b;}
void ins(int n, int x, int f)
{
int u = (1ll * (n - 1) * k + x) % ZZQ;
nxt[++ecnt] = adj[u]; adj[u] = ecnt;
gon[ecnt] = n; gok[ecnt] = x; val[ecnt] = f;
}
int query(int n, int x)
{
int u = (1ll * (n - 1) * k + x) % ZZQ;
Edge(u) if (gon[e] == n && gok[e] == x)
return val[e];
return INF;
}
void sieve()
{
int i, j;
mark[0] = mark[miu[1] = 1] = 1;
For (i, 2, MaxN)
{
if (!mark[i]) miu[pri[++tot] = i] = -1;
For (j, 1, tot)
{
if (1ll * i * pri[j] > MaxN) break;
mark[i * pri[j]] = 1;
if (i % pri[j] == 0) break;
else miu[i * pri[j]] = -miu[i];
}
}
For (i, 1, MaxN) sum[i] = sum[i - 1] + miu[i];
For (i, 1, MaxM) Step (j, i, MaxM, i)
divis[j][++divis[j][0]] = i;
For (i, 1, MaxM) ums[i] = ums[i - 1] + (__gcd(i, k) == 1);
}
int f(int n)
{
return (n / k) * ums[k] + ums[n % k];
}
int mmp;
int S(int n, int k)
{
int i, res;
if (n <= 1) return ins(n, k, n), n;
if ((res = query(n, k)) < INF) return res;
res = 0;
if (k == 1)
{
if (n <= MaxN) return sum[n];
res = 1;
Mobius (i, 2, n)
{
int nxt = n / (n / i);
res -= (nxt - i + 1) * S(n / i, k);
i = nxt + 1;
}
return ins(n, k, res), res;
}
For (i, 1, divis[k][0])
{
int x = divis[k][i];
if (miu[x] != 0) res += S(n / x, x);
}
return ins(n, k, res), res;
}
int main()
{
int i;
cin >> n >> m >> k;
sieve();
Mobius (i, 1, Min(n, m))
{
int nxt = Min(n / (n / i), m / (m / i));
ans += 1ll * (n / i) * f(m / i) * (S(nxt, k) - S(i - 1, k));
i = nxt + 1;
}
cout << ans << endl;
return 0;
}