• BZOJ3601. 一个人的数论(狄利克雷卷积+高斯消元)及关于「前 $n$ 个正整数的 $k$ 次幂之和是关于 $n$ 的 $k+1$ 次多项式」的证明


    题目链接

    https://www.lydsy.com/JudgeOnline/problem.php?id=3601

    题解

    首先还是基本的推式子:

    [egin{aligned}f_d(n) &= sum_{i = 1}^n [{ m gcd}(i, n) = 1]i^d \ &= sum_{i = 1}^n i^d sum_{k | i, k | n}mu(k) \ &= sum_{k | n} mu(k) sum_{k | i} i^d \ &= sum_{k |n} mu(k)k^d sum_{i = 1}^{frac{n}{k}}i^dend{aligned} ]

    (g(x) = sum_limits{i = 1}^x i^d),那么原式即为 $ sum_limits{k |n} mu(k)k^d g(frac{n}{k})$。

    关于函数 (g(x)),这其实是一个关于 (x)(d + 1) 次多项式。在这里我们作简要证明。也就是我们要证明「前 (n) 个正整数的 (k) 次幂之和是关于 (n)(k+1) 次多项式」。这里把我之前的一篇博客中的内容放出来。证明如下:

    (S(n, k) = sum_limits{i = 1}^{n} i^k),那么我们的目的无非是要证明 (S(n, k)) 与一个关于 (n)(k + 1) 次多项式存在某种等式关系。我们作如下考虑:

    • 我们将两个关于 (n)(k + 1) 次多项式 ((n + 1)^{k + 1})(n^{k + 1}) 相减,得到: $$egin{aligned}(n + 1)^{k + 1}-n^{k + 1} &= left(sum_{i = 0}^{k + 1}{inom{k + 1}{i}}n^i ight) - n^{k + 1} &= sum_{i = 0}^kinom{k + 1}{i}n^i end{aligned}$$ 其中,((n + 1)^{k + 1} = sum_limits{i = 0}^{k + 1}inom{k + 1}{i}n^i) 用到了二项式定理。
    • 多项式 (n^{k + 1})((n - 1)^{k + 1}) 相减,得到: $$n^{k + 1} - (n - 1)^{k + 1} = sum_{i = 0}^k inom{k + 1}{i}(n - 1)^i$$
    • (cdots)
    • 多项式 (1^{k + 1})(0^{k + 1}) 相减,得到 $$1^{k + 1} - 0^{k + 1} = sum_{i = 0}^kinom{k + 1}{i}0^i$$
    • 将上面所有式子相加,得到 $$(n + 1)^{k + 1} = sum_{i = 0}^{k}inom{k + 1}{i}S(n, i)$$

    (k = 0) 时,(S(n, 0)) 显然是一个关于 (n)(1) 次多项式。通过移项,即可得到:对于任意的 (k(k > 0)),均满足 (S(n, k)) 是一个关于 (n)(k + 1) 次多项式。

    同时,我们还能推广该结论得到:若 (f(x)) 是一个关于 (x) 的任意 (k) 次多项式,(g(x)) 满足 (g(x) = sum_limits{i = 1}^{x} f(i)),那么 (g(x)) 也是一个关于 (x)(k + 1) 次多项式。

    其证明显然,我们只需要将 (f(i)) 的各次项拆开统计到 (g(x)) 中,那么 (g(x)) 就是 (k + 1) 个形如 (a sum_limits{i = 1}^{x}i^b (0 leq b leq k)) 的关于 (x)(b + 1) 次多项式的和,即关于 (x)(k + 1) 次多项式。

    既然 (g(x)) 已经是一个关于 (x)(d + 1) 次多项式,那么我们就可以将 (g(x)) 写成多项式的一般形式,即:(g(x) = sum_limits{i = 0}^{d + 1}a_{i}x^i)。由于 (d leq 100),因此每一项的系数 (a_i) 可以通过高斯消元求得,复杂度是可接受的。我们将 (g(x)) 代入原答案式,得到:

    [egin{aligned} f_d(n) &= sum_limits{k | n} mu(k)k^d sum_limits{i = 0}^{d + 1}a_{i}left(frac{n}{k} ight)^i \ &= sum_{i = 0}^{d + 1}a_i sum_{k | n} mu(k) k^d left(frac{n}{k} ight)^iend{aligned} ]

    (h_i(x) = sum_limits{k | x} mu(k) k^d left(frac{x}{k} ight)^i),显然,(h_i) 是两个积性函数的狄利克雷卷积。因此 (h_i) 本身也是一个积性函数,由于 (n) 的唯一分解式为 (n = prod_limits{k = 1}^{w} p_k ^{alpha_k}),故有 (h_i(n) = prod_limits{k = 1}^w h_i(p_k^{alpha_k}))

    考虑如何求单个 (h_i(p ^{alpha}))

    [egin{aligned} h_i(p ^{alpha}) &= sum_{j = 0}^{alpha} mu(p^j)p^{jd} p^{(alpha - j)i}end{aligned} ]

    由于当 (j = 0) 时,(mu(p^j) = 1);当 (j = 1) 时,(mu(p^j) = -1);当 (j > 1) 时,(mu(p^j) = 0)。故有:

    [egin{aligned} h_i(p ^{alpha}) &= p^{alpha i} - p^{alpha i - i + d}end{aligned} ]

    这样,单个 (h_i(p ^ {alpha})) 就能用快速幂在 (O(log alpha)) 的时间内求出。因此,解决整个问题的时间复杂度为 (O(d^3 + dw log alpha))

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e3 + 10, mod = 1e9 + 7;
    
    void add(int& x, int y) {
      x += y;
      if (x >= mod) {
        x -= mod;
      }
    }
    
    void sub(int& x, int y) {
      x -= y;
      if (x < 0) {
        x += mod;
      }
    }
    
    int mul(int x, int y) {
      return (long long) x * y % mod;
    }
    
    int qpow(int v, int p) {
      int result = 1;
      for (; p; p >>= 1, v = mul(v, v)) {
        if (p & 1) {
          result = mul(result, v);
        }
      }
      return result;
    }
    
    int d, w, p[N], alpha[N], a[N][N];
    
    void get_coefficient() {
      int sum = 0;
      for (int i = 0; i <= d + 1; ++i) {
        add(sum, qpow(i, d));
        a[i][d + 2] = sum;
        int pow_value = 1;
        for (int j = 0; j <= d + 1; ++j) {
          a[i][j] = pow_value;
          pow_value = mul(pow_value, i);
        }
      }
      for (int i = 0; i <= d + 1; ++i) {
        int rev = i;
        for (int j = i + 1; j <= d + 1; ++j) {
          if (a[j][i]) {
            rev = j;
            break;
          }
        }
        if (rev != i) {
          for (int j = i; j <= d + 2; ++j) {
            swap(a[rev][j], a[i][j]);
          }
        }
        for (int j = i + 1; j <= d + 1; ++j) {
          int p = mul(a[j][i], qpow(a[i][i], mod - 2));
          for (int k = i; k <= d + 2; ++k) {
            sub(a[j][k], mul(a[i][k], p));
          }
        }
      }
      for (int i = d + 1; ~i; --i) {
        for (int j = i + 1; j <= d + 1; ++j) {
          sub(a[i][d + 2], mul(a[i][j], a[j][d + 2]));
        }
        a[i][d + 2] = mul(a[i][d + 2], qpow(a[i][i], mod - 2));
      }
    }
    
    int g(int i, int j) {
      int p_i = p[j], alpha_i = alpha[j];
      int c1 = (long long) alpha_i * i % (mod - 1);
      int c2 = (c1 + d - i + mod - 1) % (mod - 1);
      return (qpow(p_i, c1) - qpow(p_i, c2) + mod) % mod;
    }
    
    int main() {
      scanf("%d%d", &d, &w);
      get_coefficient();
      for (int i = 1; i <= w; ++i) {
        scanf("%d%d", &p[i], &alpha[i]);
      }
      int answer = 0;
      for (int i = 0; i <= d + 1; ++i) {
        int result = a[i][d + 2];
        for (int j = 1; j <= w; ++j) {
          result = mul(result, g(i, j));
        }
        add(answer, result);
      }
      printf("%d
    ", answer);
      return 0;
    }
    
  • 相关阅读:
    一个字段串拆分成多行显示或者多行数据合并成一个字符串
    sql server 创建登录名,并赋予访问权限
    调用CMD 执行命令
    安装 mysql
    数组和List以指定的方式拼接成字符串类型
    专业术语
    服务器读取客户端文件
    Docker基本操作
    Docker在Centos上的安装
    SpringBoot一览
  • 原文地址:https://www.cnblogs.com/ImagineC/p/10123511.html
Copyright © 2020-2023  润新知