zoukankan      html  css  js  c++  java
  • CF 1097D Makoto and a Blackboard

    算是记一下昨天晚上都想了些什么

    官方题解   点我

    简单题意

    给定两个正整数$n$和$k$,定义一步操作为把当前的数字$n$等概率地变成$n$的任何一个约数,求$k$步操作后的期望数字,模$1e9 + 7$。

    $$n leq 10^{15}, k leq 10^4$$

    我的思路

    设$f(n, k)$表示$n$在$k$步操作之后的期望数字,假设$n$的约数有$m$个,分别为$d_1, d_2, dots, d_m$,有递推式

    $$f(n, k) = frac{1}{m}sum_{i = 1}^{m}f(d_i, k - 1)$$

    边界条件显然是$f(n, 0) = n$。

    直接暴算的话一共有$n * k$个状态,无法承受。

    接下来证明:$f(a, k) * f(b, k) = f(ab, k)$,(其中$a, b$互质)。

    数学归纳法来了(逃)

    1、$k = 0$的时候显然成立。

    2、假设在$k - 1$的时候成立。

    我们设$a$有$n$个约数,$b$有$m$个约数,因为约数个数$sigma$是一个积性函数,所以$ab$的约数个数有$nm$个。

    那么根据递推式,有

    $$f(ab, k) = frac{1}{nm}sum_{d | ab}f(d, k - 1)$$

    $$f(a, k) * f(b, k) = frac{1}{n}sum_{i | a}f(i, k - 1)frac{1}{m}sum_{j | b}f(j, k - 1) = frac{1}{nm}sum_{i | a}sum_{j | b}f(i, k - 1) * f(j, k - 1)$$

    要证$f(ab, k) = f(a, k) * f(b, k)$,

    即证$sum_{d | ab}f(d, k - 1) = sum_{i | a}sum_{j | b}f(i, k - 1) * f(j, k - 1)$,

    右边的式子变形一下

    $$sum_{i | ab}sum_{j | i & j | a}f(j, k - 1) * f(frac{i}{j}, k - 1)[gcd(j, frac{i}{j} == 1)]$$

    把$ab$分解质因数变成$prod_{i = 1}^{m}p_i^{c_i}$的形式。

    注意到$a$、$b$互质,那么$gcd(j, frac{i}{j}) == 1$的时候其实只有一种,那就是$j$恰好取完了某个或某几个$p_i^{c_i}$的时候,这时候有$f(d, k - 1) = f(i, k - 1) * f(frac{d}{i}, k - 1)[gcd(d, a) == i]$。

    代进去之后发现两式相等了。

    这样子的话我们就得到了$f$函数一个类似于积性的性质,于是我们可以直接把$n$分解成$prod_{i = 1}^{m}p_i^{c_i}$的形式,然后分别计算每一个$p_i^{c_i}$的答案最后乘起来。

    发现这样子状态数十分有限,只有$klogn$个,所以直接暴力算就可以了。

    时间复杂度应当是$O(sqrt{n} + klogn)$。

    代码非常乱。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <vector>
    #include <algorithm>
    #define rep(i, a, b) for (int i = (a); i <= (b); i++)
    #define per(i, a, b) for (int i = (a); i >= (b); i--)
    using namespace std;
    typedef long long ll;
    typedef pair <ll, int> pin;
    
    const ll P = 1e9 + 7;
    
    ll ans = 1LL, g[80][10005], inv[80];
    bool vis[80][10005];
    
    map <pin, ll> mp;
    
    template <typename T>
    inline void inc(T &x, T y) {
        x += y;
        if (x >= P) x -= P; 
    }
    
    inline ll fpow(ll x, ll y) {
        ll res = 1LL;
        for (; y > 0; y >>= 1) {
            if (y & 1) res = res * x % P;
            x = x * x % P;
        }
        return res;
    }
    
    ll f(ll p, int m, int k) {
        if (p == 1) return 1LL;
        if (k == 0) return fpow(p, m);
        if (vis[m][k]) return g[m][k];
        
        vis[m][k] = 1;
        
        ll res = 0;
        rep(i, 0, m) inc(res, f(p, i, k - 1) * inv[m + 1] % P);
        
        return g[m][k] = res;
    }
    
    inline void solve(ll p, int m, int k) {
        rep(i, 0, m) rep(j, 0, k) g[i][j] = 0, vis[i][j] = 0; 
        ans = ans * f(p, m, k) % P;
    }
    
    int main() {
    //    freopen("Sample.txt", "r", stdin);
    //    freopen("out.txt", "w", stdout);
    
        rep(i, 0, 79) inv[i] = fpow(i, P - 2);
        
        ll n; int k;
        scanf("%I64d%d", &n, &k);
        
        ll tmp = n;
        for (ll i = 2; i * i <= n; i++) {
            if (tmp % i == 0) {
                int m = 0;
                for (; tmp % i == 0; tmp /= i, ++m);
                solve(i, m, k);
            }
        }    
        if (tmp > 1) solve(tmp, 1, k);
        
        printf("%I64d
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    搭建Flask+Vue及配置Vue 基础路由
    vue dev 环境下的跨域访问
    vue 调用常量的config.js文件
    PyCharm 通过Github和Git上管理代码
    MongoDB 配置服务
    2018年11月12日
    搭建 flask 应用
    Python 错误总结
    搭建 Django 平台
    go实现主线程等待子线程都运行完再退出
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10223491.html
Copyright © 2011-2022 走看看