zoukankan      html  css  js  c++  java
  • cf1139D-Steps to One

    此题学到一招,就是将概率dp转化为DAG图
    考虑概率f[],设f[i]表示当前数组的gcd为i是走向gcd为1的期望步数,因为每次可以选择一个数(1 , m) ,添加到结尾,所以相当于每次从当前x点走向gcd(x , k) , 所以从每个点走,都有m条路径,,最后加一个虚点, 连接第一次选择的数,所以答案也就相当于从虚点走向1,只要求从虚点走向第一次选择的点就可, 答案: $$ans = 1 + frac{sum_{1}^{m}{f[i]}}{m}$$

    考虑怎么求f[n] , 从点n可以走向(d , [d | n]) , 所以 $$f[n] = 1 + frac{sum_{i = 1}^{m}{f[gcd(n , i)]}}{m}$$

    [\=>m * f[n] = m + sum_{i = 1}^{m}{f[gcd(n , i)]} ]

    [\=>m * f[n] = m + sum_{d |n}{f[d] * sum[gcd(n , i) == d]}$$**下面是莫比乌斯反演** $$\=>sum_{i = 1}^{m}[gcd(n , i) == d]]

    [\=>sum_{i = 1}^{frac{m}{d}}[gcd(frac{n}{d} , i) == 1] ]

    [\=>sum_{i = 1}^{frac{m}{d}}sum_{t|gcd(frac{n}{d} , i)}mu(t) ]

    [\=>sum_{i = 1}^{frac{m}{d}}sum_{t|frac{n}{d} &t|i}mu(t) ]

    [\=>sum_{t|frac{n}{d}}mu(t) * lfloorfrac{m}{d*t} floor ]

    [带回原式 ]

    [=>m * f[n] = m + sum_{d |n}{f[d] * (sum_{t|frac{n}{d}}mu(t) * lfloorfrac{m}{d*t} floor)} ]

    这个时候发现在枚举d的时候d有可能等于n, n也是n的约数, 拿出来之后

    [m * f[n] = m + sum_{d |n&d!=n}{f[d] * (sum_{t|frac{n}{d}}mu(t) * lfloorfrac{m}{d*t} floor)} + f[n] * lfloorfrac{m}{n} floor ]

    [=>f[n] = frac{m + sum_{d |n&d!=n}{f[d] * (sum_{t|frac{n}{d}}mu(t) * lfloorfrac{m}{d*t} floor)}}{m - lfloorfrac{m}{n} floor} + ]

    这个复杂度我不知道是怎么过的,先预处理出来(mu(t))预处理每个数的约数, 然后先枚举n,再枚举d,最后枚举t

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    typedef long long ll ;
    const double esp = 1e-6 , pi = acos(-1) ;
    typedef pair<int , int> PII ;
    const int N = 2e5 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
    ll in()
    {
    ll x = 0 , f = 1 ;
    char ch = getchar() ;
    while(!isdigit(ch)) {if(ch == '-') f = -1 ; ch = getchar() ;}
    while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
    return x * f ;
    }
    ll mu[N] , tot , prime[N] , vis[N] , f[N] , inv[N] ;
    vector<ll> v[N] ;
    int main()
    {
    ll m = in() ;
    mu[1] = 1 ;
    for(ll i = 2; i < N ;i ++ ) {
      if(!vis[i]) prime[++ tot] = i , mu[i] = -1 ;
      for(ll j = 1 ;j <= tot && i * prime[j] < N ;j ++ )
       {
         vis[i * prime[j]] = 1 ;
         if(i % prime[j] == 0) break ;
         mu[i * prime[j]] = - mu[i] ;
       }
    }
    inv[1] = 1 ;
    for(ll i = 2; i < N ;i ++ )
     inv[i] = (mod - mod / i) * inv[mod % i] % mod ;
    f[1] = 0 ;
    for(ll i = 1; i < N ;i ++ ) {
      for(ll j = i ;j < N ;j += i)
       v[j].push_back(i) ;
    }
    for(ll i = 2; i <= m ;i ++ ) {
      ll n = i ;
      ll ans = m ;
      for(auto d : v[n]) {
        if(d == n) break ;
        ll res = 0 ;
        for(auto t : v[n / d]) {
          res += mu[t] * (m / d / t) % mod ;
          res %= mod ;
        }
        res = res * f[d] % mod ;
        (ans += res) %= mod ;
      }
      ans = ans * inv[m - m / n] % mod ;
      f[i] = ans ;
    }
    ll ans = 0 ;
    for(int i = 1; i <= m ;i ++ )
     (ans += f[i]) %= mod ;
    ans = ans * inv[m] % mod ;
    ans ++ ;
    cout << ans << endl ;
    return 0 ;
    }
    /*
    */
    
    
  • 相关阅读:
    python基础(十七、变量进阶
    python基础(十六、变量进阶
    python基础(十五、变量进阶
    python基础(十四、变量进阶
    python基础(十三、综合应用
    MySQL-索引失效原理
    MySQL-忘记密码
    OSI七层模型
    Python-socket通信
    Python-编程小技巧
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/13286242.html
Copyright © 2011-2022 走看看