[NOI2016]循环之美


题意

牛牛是一个热爱算法设计的高中生。在他设计的算法中,常常会使用带小数的数进行计算。牛牛认为,如果在 \(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.1\dot6\)则不是纯循环的,它可以用 \(1/6\) 等分数表示。需要特别注意的是,我们认为一个整数是纯循环的,因为它的小数部分可以表示成 \(0\) 的循环或是 \(k-1\) 的循环;而一个小数部分非 \(0\) 的有限小数不是纯循环的。

输入输出格式

输入格式:

只有一行,包含三个十进制数N,M,K意义如题所述,保证 1≤n≤10^9,1≤m≤10^9,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\)的时候才计算\(\sum\mu\),否则就枚举因数继续计算

代码

#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\n",ans) ;
    return 0 ;
}
优质内容筛选与推荐>>
1、学习笔记:大话数据结构(二)
2、企业级系统架构的理解
3、Java Web 重要的方法 -----学习过程总结的(不全,后续会继续补充)
4、jackson 进行json与java对象转换 之四
5、代码重构


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号