QwQ

这道题思路还算是比较好想.jpg

但是有些细节的东西比如证明复杂度我感觉我特别是 CF 比赛的时候不可能静下心来想到的

好吧我们讲题解

题解

首先我们设 $dp_x$表示 $gcd$到 $x$的时候还要期望 $dp_x$次才能到 $1$

显然 $dp_1=0$

对于 $x\geq 2$,我们有

$$dp_x=1+\sum_{y=1}^m \frac {dp_{gcd(x,y)}}{n}$$

然后你可以建一张图然后跑高斯消元

然后你可以发现我们可以枚举 $gcd$

$$dp_x=1+\sum_{d|x} \frac{f_{x,d}dp_d}{n}$$

这里 $f_{x,d}=\sum_{y=1}^m [gcd(x,y)==d]$

上面的递推式在 $f$已知的情况下已经可以 $O(nlogn)$求解了。

考虑如何预处理 $f$

我们可以假设我们已经处理出了 $f_{x,d+1}$到 $f_{x,dmax}$,现在需要求 $f_{x,d}$

显然我们知道 $\frac m d = \sum_{y=1}^m[gcd(x,y) == kd]$,这里 $k\in N_+$

我们再将它减去 $f_{x,2d},f_{x,3d}…$就可以求出 $f_{x,d}$了

我们记 $d_x$表示 $x$的因数个数

$d_1+…+d_n=nlogn$

我们的复杂度为 $d_1^2+…+d_n^2$,由均值不等式得时间复杂度为 $O(nlog^2n)$

当然我们这里也可以用莫比乌斯反演来做,但是时间复杂度貌似也是两个 $log$的 (不过貌似常数小很多)

代码

#include<bits/stdc++.h> 
#define fo(i, a, b) for (int i = (a); i <= (b); ++i)
#define fd(i, a, b) for (int i = (a); i >= (b); --i)
#define edge(i, u) for (int i = head[u], v = e[i].v; i; i = e[i].nxt, v = e[i].v)
#define pb push_back
#define F first
#define S second
#define ll long long
#define inf 1000000007
#define mp std::make_pair
#define ls (u << 1)
#define rs (u << 1 | 1)
#define mod 1000000007
#define eps 1e-4
#define N 100005
using std::vector;
int n;
ll dp[N], ans, invn;
vector<int> d[N], f[N];
inline void sieve ()
{
    fo (i, 1, n)
    {
        for (int j = i; j <= n; j += i)
            d[j].pb(i);
        std::reverse(d[i].begin(), d[i].end());
    }
    fo (i, 1, n)
    {
        int sz = d[i].size() - 1;
        fo (j, 0, sz)
        {
            int now = n / d[i][j];
            fo (k, 0, j - 1)
            {
                if (!(d[i][k] % d[i][j]))
                    now -= f[i][k];
            }
            f[i].pb(now);
        }
    }
}
inline ll pow (ll x, int y)
{
    ll ret = 1;
    while (y)
    {
        if (y & 1) ret = ret * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ret;
}
int main ()
{
    scanf("%d", &n);
    sieve();
    invn = pow(n, mod - 2);
    fo (i, 2, n)
    {
        int sz = d[i].size() - 1;
        dp[i] = 1;
        fo (j, 1, sz)
            (dp[i] += dp[d[i][j]] * f[i][j] % mod * invn) %= mod;
        dp[i] = dp[i] * pow((1 - f[i][0] * invn % mod + mod) % mod, mod - 2) % mod;
    }
    ans = 1;
    fo (i, 1, n) (ans += dp[i] * invn) %= mod;
    printf("%lld", ans);
    return 0;
}
分类: 文章

quhengyi11

AFO 有缘再见

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注