[BZOJ4652/UOJ#221][NOI2016]循环之美(莫比乌斯反演+杜教筛)

Address

https://www.lydsy.com/JudgeOnline/problem.php?id=4652
http://uoj.ac/problem/221

Solution……

一、 O ( n m )

我们知道, k 进制小数 0.0000000...10000000..10000000..1... (循环节为 x 1 0 1 1 )等于 1 k x 1
于是,乱搞一下 gcd ( x , y ) = 1 x y 纯循环当且仅当存在一个 z > 0 满足 y | k z 1
于是:

k z 1 ( mod y )

如果 gcd ( k , y ) 1 则易得上面的方程无解。否则根据欧拉定理,一个合法解是 z = ϕ ( y )
于是,我们要求的答案为:
i = 1 n j = 1 m [ gcd ( i , j ) = 1 ] [ gcd ( j , k ) = 1 ]

二、反演

上式 =

j = 1 m [ gcd ( j , k ) = 1 ] i = 1 n [ gcd ( i , j ) = 1 ]

= j = 1 m [ gcd ( j , k ) = 1 ] i = 1 n d | gcd ( i , j ) μ ( d )

= d μ ( d ) n d j = 1 , d | j m [ gcd ( j , k ) = 1 ]

= d μ ( d ) n d j = 1 m d [ gcd ( j d , k ) = 1 ]

= d = 1 min ( n , m ) [ gcd ( d , k ) = 1 ] μ ( d ) n d j = 1 m d [ gcd ( j , k ) = 1 ]

d 下界分块即可。
可以考虑求:
f ( n ) = i = 1 n [ gcd ( i , k ) = 1 ]

使得该式变为:
a n s = d = 1 min ( n , m ) [ gcd ( d , k ) = 1 ] μ ( d ) n d f ( m d )

由于 n d 的取值只有 O ( n ) 种, m d 的取值只有 O ( m ) 种,故可对 d 下界分块,需要求出 [ gcd ( d , k ) = 1 ] μ ( d ) 的前缀和:
g ( n , k ) = i = 1 n [ gcd ( i , k ) = 1 ] μ ( i )

三、解决掉 f

我们知道, gcd ( a , b ) = gcd ( a + k × b , b )
于是:

f ( n ) = n k ϕ ( k ) + i = 1 n mod k [ gcd ( i , k ) = 1 ]

预处理出 c n t [ i ] 表示 [ 1 , i ] 中与 k 互质的数的个数之后,就可以 O ( 1 ) f

四、解决掉 g

考虑再反演一次:

g ( n , k ) = d | k μ ( d ) i = 1 , d | i n μ ( i )

= d | k μ ( d ) i = 1 n d μ ( i d )

众所周知, μ 是个积性函数,且有:
μ ( a b ) = { m u ( a ) × m u ( b ) gcd ( a , b ) = 1 0 gcd ( a , b ) 1

故:
g ( n , k ) = d | k μ ( d ) 2 i = 1 n d [ gcd ( i , d ) = 1 ] μ ( i ) = d | k μ ( d ) 2 g ( n d , d )

我们得到 g ( n , k ) 的递推式,可用记忆化搜索求得。
特别地,由于任意都与 1 互质,故 g ( n , 1 ) = i = 1 n μ ( i ) 。故当 k = 1 时杜教筛即可。

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

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/82660326
今日推荐