题意
牛牛是一个热爱算法设计的高中生。在他设计的算法中,常常会使用带小数的数进行计算。牛牛认为,如果在 (k) 进制下,一个数的小数部分是纯循环的,那么它就是美的。现在,牛牛想知道:对于已知的十进制数 (n) 和 (m),在 (k) 进制下,有多少个数值上互不相等的纯循环小数,可以用分数 (frac xy) 表示,其中 (1≤x≤n,1≤y≤m),且 (x,y)是整数。一个数是纯循环的,当且仅当其可以写成以下形式:
(a.dot{c_1} c_2 c_3 dots c_{p - 1} dot{c_p})
其中,(a) 是一个整数,(p≥1);对于 (1≤i≤p),(c_i) 是 (k) 进制下的一位数字。
例如,在十进制下,(0.45454545……=0.dot {4} dot {5})是纯循环的,它可以用 (frac {5}{11})、(frac{10}{22}) 等分数表示;在十进制下,(0.1666666……=0.1dot6)则不是纯循环的,它可以用 (1/6) 等分数表示。需要特别注意的是,我们认为一个整数是纯循环的,因为它的小数部分可以表示成 (0) 的循环或是 (k-1) 的循环;而一个小数部分非 (0) 的有限小数不是纯循环的。
输入输出格式
输入格式:
只有一行,包含三个十进制数N,M,K意义如题所述,保证 1≤n≤109,1≤m≤109,2≤k≤2000
输出格式:
一行一个整数,表示满足条件的美的数的个数。
输入输出样例
输入样例#1:
2 6 10
输出样例#1:
4
题解
自闭==
好难啊,推了半天实在不会推式子的前半部分的那些东西
题目就是让求(sum_{i=1}^{n}sum_{j=1}^{m}{[gcd(i,j)=1][gcd(j,k)=1]})
(sum_{i=1}^{n}sum_{j=1}^{m}{[gcd(i,j)=1][gcd(j,k)=1]})
先考虑前面的(sum_{i=1}^{n}sum_{j=1}^{m}{[gcd(i,j)=1]})
很显然是(sum_{d=1}^{n}{mu(d)frac{n}{d}frac{m}{d}})
那现在式子就成了(sum_{d=1}^{n}{mu(d)frac{n}{d}}sum_{i=1}^{m/d}{[gcd(id,k)=1]})
这样的话(d)就必须满足(gcd(d,k)=1)
所以(sum_{d=1}^{n}{[gcd(d,k)=1]mu(d)frac{n}{d}}sum_{i=1}^{m/d}{[gcd(i,k)=1]})
先看后面的那一部分:
如果(frac{m}{d} | k)
那么答案就是(frac{m}{dk}phi(k))
对于剩下的那(frac{m}{d} \% k)的部分
我们暴力预处理出来就行了
所以后面的部分等于(frac{m}{dk}phi(k)+F(frac{m}{d} \% k))
这么一看我们只需要再求出一个(S(n,k)=sum_{d=1}^{n}{[gcd(d,k)=1]mu(d)})就行了
但是由于有一个限制,所以并不好筛
(sum_{d=1}^{n}{[gcd(d,k)=1]mu(d)}\=sum_{d=1}^{n}{mu(d)}sum_{t|gcd(d,k)}{mu(t)}\=sum_{d=1}^{n}{mu(d)}sum_{t|d,t|k}{mu(t)})
由于需要(t|d,t|k),所以(t<=k),所以满足条件的(d)一定是(d|k)
(\=sum_{d|k}{mu(d)}sum_{t|d}{mu(t)})
(=sum_{d|k}{mu(d)}sum_{t=1}^{n/d}{mu(dt)})
(mu(dt))不为0的话必须要满足(gcd(d,t)=1)
(=sum_{d|k}{mu(d)}sum_{t=1,gcd(d,t)=1}^{n/d}{mu(d)mu(t)}\=sum_{d|k}{mu(d)^2}sum_{t=1,gcd(d,t)=1}^{n/d}{mu(t)}\=sum_{d|k}{mu(d)^2}S(frac{n}{d},d))
这样就可以杜教筛+记搜了
只有(d=1)的时候才计算(summu),否则就枚举因数继续计算
代码
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define MP(x , y) (make_pair(x , y))
# define LL long long
const int M = 4000005 ;
using namespace std ;
bool notp[M] ;
int p[M] , pnum , mu[M] ;
LL n , m , k , upp = 4000000 ;
LL sum[M] , f[M] , ans ;
map < pair < LL , LL > , LL > pi ;
inline int gcd(int a , int b) {
if(b == 0) return a ;
return gcd(b , a % b) ;
}
inline void presolve(int n) {
sum[1] = 1 ;
for(int i = 2 ; i <= n ; i ++) {
if(!notp[i]) {
p[++pnum] = i ;
sum[i] = -1 ;
}
for(int j = 1 ; j <= pnum && 1LL * i * p[j] <= n ; j ++) {
notp[i * p[j]] = true ;
if(i % p[j] == 0) {
sum[i * p[j]] = 0 ;
break ;
}
else sum[i * p[j]] = - sum[i] ;
}
}
for(int i = 1 ; i <= n ; i ++) {
mu[i] = sum[i] ;
sum[i] = sum[i - 1] + sum[i] ;
}
for(int i = 1 ; i <= k ; i ++)
f[i] = f[i - 1] + (gcd(i , k) == 1) ;
}
inline LL F(LL n) {
return f[k] * (n / k) + f[n % k] ;
}
inline LL Sum(LL n , LL k) {
if(n == 0) return 0 ;
if(k == 1 && n <= upp) return sum[n] ;
if(pi[MP(n , k)]) return pi[MP(n , k)] ;
LL ret = 0 ;
if(k == 1) {
ret = 1 ;
for(LL l = 2 , r ; l <= n ; l = r + 1) {
r = n / (n / l) ;
ret -= (r - l + 1) * Sum(n / l , k) ;
}
}
else {
for(int x = 1 , y ; x * x <= k ; x ++) {
if(k % x) continue ;
if(mu[x])
ret += Sum(n / x , x) ;
y = k / x ;
if(x == y) continue ;
if(mu[y])
ret += Sum(n / y , y) ;
}
}
pi[MP(n , k)] = ret ;
return ret ;
}
int main() {
scanf("%lld%lld%lld",&n,&m,&k) ;
presolve(4000000) ;
for(LL l = 1 , r ; l <= min(n , m) ; l = r + 1) {
r = min(n / (n / l) , m / (m / l)) ;
ans += (Sum(r , k) - Sum(l - 1 , k)) * (n / l) * F(m / l) ;
}
printf("%lld
",ans) ;
return 0 ;
}