zoukankan      html  css  js  c++  java
  • Codeforces #548 (Div2)

    Problem   Codeforces #548 (Div2) - D.Steps to One

    Time Limit: 2000 mSec

    Problem Description

    Input

     The first and only line contains a single integer mm (1m100000,1≤m≤100000).

    Output

    Print a single integer — the expected length of the array aa written as PQ^1(mod10^9+7)

    Sample Input

     4

    Sample Output

    333333338

    题解:概率dp做的太少了,不会做。。。

      首先是状态定义,dp[x]表示当前序列的gcd为x的情况下,还能添加数字个数的期望值,看了题解之后感觉这样很自然,但是自己想就想不到,有了这个定义之后状态转移就比较简单了,枚举下一个数字,根据期望的线性性质,有:

      

    这样一来得到了一个O(n^2)的算法,显然不行,不过到这里的转化就很套路了,枚举gcd,式子化为:

      

    f(y, x)指的是和x的gcd是y的数有多少个(从1到m),预处理出1~m的约数,复杂度mlogm,这样不用根号m枚举约数,枚举y这一步题解中给出的均摊复杂度是logm,(不会证qwq,不过很多地方都是这么分析的),这样一来就只剩下f的求解了,设x = y * a,则和x的gcd为b的数必定可表达为 p = y * b且gcd(a, b) = 1,这样一来就相当于计算从1到m/y中和a互质的数的个数,也就是和a没有相同的质因子,打打表(看题解)可以发现在题目的范围内b的质因子数至多为6,容斥一下即可计数,最终复杂度O(mlogm*2^6*6),是可以接受的。代码是看了题解的代码之后写的,主要学习这里质因数分解的操作。

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 #define REP(i, n) for (int i = 1; i <= (n); i++)
      6 #define sqr(x) ((x) * (x))
      7 
      8 const int maxn = 100000 + 100;
      9 const int maxm = 200000 + 100;
     10 const int maxs = 10000 + 10;
     11 
     12 typedef long long LL;
     13 typedef pair<int, int> pii;
     14 typedef pair<double, double> pdd;
     15 
     16 const LL unit = 1LL;
     17 const int INF = 0x3f3f3f3f;
     18 const LL mod = 1000000007;
     19 const double eps = 1e-14;
     20 const double inf = 1e15;
     21 const double pi = acos(-1.0);
     22 
     23 LL pow_mod(LL x, LL n, LL mod)
     24 {
     25     LL base = x % mod;
     26     LL ans = 1;
     27     while (n)
     28     {
     29         if (n & 1)
     30         {
     31             ans = ans * base % mod;
     32         }
     33         base = base * base % mod;
     34         n >>= 1;
     35     }
     36     return ans % mod;
     37 }
     38 
     39 LL m, invm;
     40 unordered_map<int, int> prime[maxn];
     41 vector<LL> fact[maxn];
     42 bool is_prime[maxn];
     43 LL dp[maxn];
     44 
     45 void premanagement()
     46 {
     47     memset(is_prime, true, sizeof(is_prime));
     48     is_prime[0] = is_prime[1] = false;
     49     for (LL i = 2; i < maxn; i++)
     50     {
     51         if (is_prime[i])
     52         {
     53             for (LL j = i; j < maxn; j += i)
     54             {
     55                 LL cnt = 0;
     56                 LL tmp = j;
     57                 while (tmp % i == 0)
     58                 {
     59                     cnt++;
     60                     tmp /= i;
     61                 }
     62                 prime[j][i] = cnt;
     63                 is_prime[j] = false;
     64             }
     65             is_prime[i] = true;
     66         }
     67     }
     68 
     69     for (LL i = 1; i < maxn; i++)
     70     {
     71         for (LL j = 2 * i; j < maxn; j += i)
     72         {
     73             fact[j].push_back(i);
     74         }
     75     }
     76 }
     77 
     78 LL cal(LL x, LL n)
     79 {
     80     vector<LL> a;
     81     LL curcnt = m / x;
     82     for (auto &item : prime[n])
     83     {
     84         if (!prime[x].count(item.first))
     85         {
     86             a.push_back(item.first);
     87             continue;
     88         }
     89         if (prime[x][item.first] == item.second)
     90         {
     91             continue;
     92         }
     93         else
     94         {
     95             a.push_back(item.first);
     96         }
     97     }
     98 
     99     LL sz = a.size();
    100     LL lim = m / x;
    101     for (LL sit = 1; sit < (unit << sz); sit++)
    102     {
    103         LL tag = 1;
    104         LL val = 1;
    105         for (LL j = 0; j < sz; j++)
    106         {
    107             if (sit & (unit << j))
    108             {
    109                 val *= a[j];
    110                 tag *= -1;
    111             }
    112         }
    113         curcnt += tag * (lim / val);
    114     }
    115     return curcnt;
    116 }
    117 
    118 int main()
    119 {
    120     ios::sync_with_stdio(false);
    121     cin.tie(0);
    122     //freopen("input.txt", "r", stdin);
    123     //freopen("output.txt", "w", stdout);
    124     cin >> m;
    125     invm = pow_mod(m, mod - 2, mod);
    126     premanagement();
    127     dp[1] = 0;
    128     for (LL i = 2; i <= m; i++)
    129     {
    130         LL &ans = dp[i];
    131         ans = 1;
    132         for (LL item : fact[i])
    133         {
    134             ans += cal(item, i) * dp[item] % mod * invm % mod;
    135             ans %= mod;
    136         }
    137         LL cnt = m / i;
    138         ans = ans * m % mod * pow_mod(m - cnt, mod - 2, mod) % mod;
    139     }
    140     LL ans = 1;
    141     for (LL i = 1; i <= m; i++)
    142     {
    143         ans = (ans + dp[i] * invm) % mod;
    144     }
    145     cout << ans << endl;
    146     return 0;
    147 }
  • 相关阅读:
    面试题-酷家乐面试准备
    英语学习-第一次申请试译的小透明(未完待续)
    操作系统educative版本-笔记1
    周末日记-第一次相对正规的技术教学
    资料推荐-一个神奇的网站educative.io
    面试题-持续集成
    每天5分钟玩转容器技术-读书笔记-第六章
    每天5分钟玩转容器技术-读书笔记-第四章到第五章
    工作日记-文件柜驱动层开发总结
    DP套题练习1
  • 原文地址:https://www.cnblogs.com/npugen/p/10779083.html
Copyright © 2011-2022 走看看