zoukankan      html  css  js  c++  java
  • [Codeforces 1139D] Steps to One

    [题目链接]

             https://codeforces.com/contest/1139/problem/D

    [算法]

            考虑dp

            设fi表示现在gcd为i , 期望多少次gcd变为1

            显然 , fi = (1 / m) * sigma{ fgcd(i , j) } + 1

            直接转移是O(N ^ 2logN)的 , 显然不能通过

            考虑在转移时枚举gcd , 显然gcd只可能是i的约数 , 可以在dp前O(NlogN)预处理每个数的约数

            于是问题转化为求一个形如 : [1 , m]中有多少个数与i的gcd为j的问题

            这等价于求 : [1 , m / j]中有多少个数与(i / j)的gcd为1

            容斥原理计算即可

            时间复杂度 : O(NlogN)( 有较大的常数 )

    [代码]

            

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int P = 1e9 + 7;
    const int MAXP = 1e5 + 10;
    
    #define rint register int
    
    int m , tot;
    int f[MAXP] , prime[MAXP] , dp[MAXP];
    vector< int > d[MAXP];
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    inline int exp_mod(int a , int n)
    {
            int b = a , res = 1;
            while (n > 0)
            {
                    if (n & 1) res = 1LL * res * b % P;
                    b = 1LL * b * b % P;
                    n >>= 1;
            }
            return res;
    }
    inline int calc(int N , int M)
    {
            vector< int > pr;
            int tmp = N / M;
            while (tmp != 1)
            {
                    pr.push_back(f[tmp]);
                    tmp /= f[tmp];        
            }    
            int sz = unique(pr.begin() , pr.end()) - pr.begin(); 
            int limit = m / M , res = 0;
            for (int i = 0; i < (1 << sz); ++i)
            {
                    int sign = 1 , val = 1;
                    for (int j = 0; j < sz; ++j)
                    {
                            if (i & (1 << j))
                            {
                                    sign *= -1;
                                    val *= pr[j];
                            } 
                    }
                    res += 1LL * sign * (limit / val);
            }
            return res;
    }
    
    int main()
    {
            
            read(m);
            for (rint i = 1; i <= m; ++i)
            {
                    for (rint j = i; j <= m; j += i)
                    {
                            d[j].push_back(i);                
                    }
            }
            for (rint i = 2; i <= m; ++i)
            {
                    if (!f[i])
                    {
                            prime[++tot] = i;
                            f[i] = i;
                    }
                    for (int j = 1; j <= tot; ++j)
                    {
                            int tmp = i * prime[j];
                            if (tmp >= MAXP) break;
                            f[tmp] = prime[j];
                            if (prime[j] == f[i]) break;
                    } 
            }
            dp[1] = 1;
            for (rint i = 2; i <= m; ++i)
            {
                    int res = 0;
                    for (unsigned j = 0; j < d[i].size(); ++j)
                    {
                            int D = d[i][j];
                            if (D != i) res = (res + 1LL * calc(i , D) * dp[D] % P) % P;
                    }
                    res = 1LL * res * exp_mod(m , P - 2) % P;
                    res = (res + 1) % P;
                    int fm = m - calc(i , i);
                    res = 1LL * res * exp_mod(fm , P - 2) % P * m % P;
                    dp[i] = res;
            }
            int ans = 0;
            for (rint i = 1; i <= m; ++i) ans = (ans + 1LL * exp_mod(m , P - 2) * dp[i] % P) % P;
            printf("%d
    " , ans);
            
            return 0;
        
    }

             

  • 相关阅读:
    PAT顶级 1015 Letter-moving Game (35分)
    PAT顶级 1008 Airline Routes (35分)(有向图的强连通分量)
    PAT顶级 1025 Keep at Most 100 Characters (35分)
    PAT顶级 1027 Larry and Inversions (35分)(树状数组)
    PAT 顶级 1026 String of Colorful Beads (35分)(尺取法)
    PAT顶级 1009 Triple Inversions (35分)(树状数组)
    Codeforces 1283F DIY Garland
    Codeforces Round #438 A. Bark to Unlock
    Codeforces Round #437 E. Buy Low Sell High
    Codeforces Round #437 C. Ordering Pizza
  • 原文地址:https://www.cnblogs.com/evenbao/p/10660089.html
Copyright © 2011-2022 走看看