Codeforces1139D_CF1139DSteps to One (Mobius_DP)

Posted zyt1253679098

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces1139D_CF1139DSteps to One (Mobius_DP)相关的知识,希望对你有一定的参考价值。

Problem:

Codeforces 1139D

Analysis:

After ACing E, I gave up D and spent the left 30 minutes chatting with Little Dino.

Let (f[n]) be the expected number of steps needed to make the greatest common divisor (gcd) become (1) when the gcd is (n) now, and (g(n,d)) be the number of (x(xin[1,m])) that (gcd(x, n)=d) . So we have:

[f[n]=1+sum_{d|n}frac{f[d]cdot g(n, d)}{m}]

To make it easy, multiply (m) to the equation:

[mf[n]=m+sum_{d|n}f[d]cdot g(n, d)]

Notice that (d) can be (n), and (g(n,n)) is (lfloorfrac{m}{n} floor), so we have:

[(m-lfloorfrac{m}{n} floor)f[n]=m+sum_{d|n,d eq n}f[d]cdot g(n, d)]

Now the problem become how to calculate (g(n,d)). According to the defination,

[ egin{aligned} g(n, d)&=sum_{i=1}^m[gcd(n, i)=d]&=sum_{i=1}^{lfloorfrac{m}{d} floor}[gcd(frac{n}{d},i)=1]&=sum_{i=1}^{lfloorfrac{m}{d} floor}epsilonleft(gcd(frac{n}{d},i) ight)\end{aligned} ]

where (epsilon(x)=egin{cases}1 (x=1)\0 mathrm{otherwise}end{cases}) .

According to the Mobius Theorem ( (mu * 1 = epsilon) ) :

[ egin{aligned} g(n,d)&=sum_{i=1}^{lfloorfrac{m}{d} floor}sum_{t|frac{n}{d},t|i}mu(t)&=sum_{t|frac{n}{d}}mu(t)cdot lfloor frac{m}{dt} floor end{aligned} ]

Let‘s return to (f[n]):

[(m-lfloorfrac{m}{n} floor)f[n]=m+sum_{d|n,d eq n}f[d]sum_{t|frac{n}{d}}mu(t)cdot lfloor frac{m}{dt} floor]

Preprocess the divisors of all integer (x(xin[1,m])) and then calculate (f[n]) as the equation above directly. Because the number of divisors of most integers is very small ( for integers not more than (100000), the maximum is (128) and the total number is about (10^6) to (2 imes 10^6)) , so it won‘t TLE.

At last, the answer is:

[ans=1+sum_{i=1}^{m}frac{f[i]}{m}]

Code:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>
using namespace std;

namespace zyt
{
    typedef long long ll;
    const int N = 1e5 + 10, p = 1e9 + 7;
    vector<int> fac[N];
    int n, f[N], pcnt, prime[N], mu[N];
    bool mark[N];
    void init()
    {
        for (int i = 1; i <= n; i++)
            for (int j = 1; j * j <= i; j++)
                if (i % j == 0)
                {
                    fac[i].push_back(j);
                    if (j * j != i)
                        fac[i].push_back(i / j);
                }
        mu[1] = 1;
        for (int i = 2; i <= n; i++)
        {
            if (!mark[i])
                prime[pcnt++] = i, mu[i] = p - 1;
            for (int j = 0; j < pcnt && (ll)i * prime[j] <= n; j++)
            {
                int k = i * prime[j];
                mark[k] = true;
                if (i % prime[j] == 0)
                {
                    mu[k] = 0;
                    break;
                }
                else
                    mu[k] = p - mu[i];
            }
        }
    }
    int power(int a, int b)
    {
        int ans = 1;
        while (b)
        {
            if (b & 1)
                ans = (ll)ans * a % p;
            a = (ll)a * a % p;
            b >>= 1;
        }
        return ans;
    }
    int inv(const int a)
    {
        return power(a, p - 2);
    }
    int work()
    {
        scanf("%d", &n);
        init();
        f[1] = 0;
        int ans = 0;
        for (int i = 2; i <= n; i++)
        {
            for (int j = 0; j < fac[i].size(); j++)
            {
                int d = fac[i][j];
                if (d == i)
                    continue;
                int tmp = 0;
                for (int k = 0, size = fac[i / d].size(); k < size; k++)
                {
                    int t = fac[i / d][k];
                    tmp = (tmp + (ll)mu[t] * (n / d / t) % p) % p;
                }
                f[i] = (f[i] + (ll)tmp * f[d] % p) % p;
            }
            f[i] = (ll)(f[i] + n) * inv(n - n / i) % p;
        }
        for (int i = 1; i <= n; i++)
            ans = (ans + f[i]) % p;
        printf("%d", int(((ll)ans * inv(n) % p) + 1) % p);
        return 0;
    }
}
int main()
{
    return zyt::work();
}

以上是关于Codeforces1139D_CF1139DSteps to One (Mobius_DP)的主要内容,如果未能解决你的问题,请参考以下文章

codeforces1139E Maximize Mex 二分图匹配

Codeforces 1139F Dish Shopping 树状数组套平衡树 || 平衡树

cf 1139D - Steps to One

1139: [POI2009]Wie

XDOJ_1139_二分查找

1139 约瑟夫环问题