没想到每日一题也会有黑题

期望DP

为当前时需要走步才能到达1,有

其中表示中有使得,可以容斥处理

时间复杂度

CODE

#include <algorithm>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <iomanip>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define int long long
#define I inline
#define ri register int
#define For(i , x , y) for(ri i = x ; i <= y ; ++ i)
#define Next(i , x) for(ri i = head[x] ; i ; i = e[i].nxt)
#define pb(x) push_back(x)

I int read() {
    int s = 0 , w = 1; char ch = getchar();
    while(ch < 48 || ch > 57) {if(ch == '-') w = -1; ch = getchar();}
    while(ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48) , ch = getchar();
    return s * w;
}

const int N = 1e5 + 5 , P = 1e9 + 7;

int n , f[N];
vector <int> d[N] , cnt[N];

I int qpow(int x , int y) {
    int res = 1;
    for( ; y ; x = (x * x) % P , y >>= 1)
        if(y & 1) res = (res * x) % P ;
    return res;
}

I int inv(int x) {
    return qpow(x , P - 2);
}


signed main() {
    n = read();
    For(i , 1 , n)
        for(int j = i ; j <= n ; j += i)
            d[j].pb(i) , cnt[j].pb(0);
    For(i , 1 , n)
        for(int j = d[i].size() - 1 ; j >= 0 ; -- j) {
            cnt[i][j] = n / d[i][j];
            for(int k = j + 1 ; k < d[i].size() ; ++ k)
                if(d[i][k] % d[i][j] == 0) cnt[i][j] -= cnt[i][k];
        }
    f[1] = 0;
    For(i , 2 , n) {
        int sum = 0 ,x = 0;
        for(int j = 0 ; j < d[i].size() ; ++ j) {
            if(d[i][j] == i) sum = (sum + cnt[i][j]) % P ;
            else x = (x + f[d[i][j]] * cnt[i][j] % P) % P;
        }
        f[i] = (x + n) % P * inv((n - sum + P) % P) % P;
    }
    int ans = 0;
    For(i , 1 , n) ans = (ans + f[i] + 1) % P;
    cout << ans * inv(n) % P << endl;
    return 0;
}
/*
dp[i] = \sum{ dp[gcd(i , j)] } / m + 1
    = 
*/