zoukankan      html  css  js  c++  java
  • [Bzoj 2956] 模积和 (整除分块)

    整除分块

     一般形式:(sum_{i = 1}^n lfloor frac{n}{i} floor * f(i))
     需要一种高效求得函数 (f(i)) 的前缀和的方法,比如等差等比数列求和或对于积性函数的筛法等,然后就可以用整除分块的思想做。
     

    题目解法

     化公式变成比较方便的形式:
      ( sum_{i = 1}^n sum_{j = 1}^m (n mod i)(m mod j), i e j)
     (= sum_{i = 1}^n sum_{j = 1}^m (n - i lfloor frac{n}{i} floor)(m - j lfloor frac{m}{j} floor) - sum_{i = 1}^{min(n, m)} (n - i lfloor frac{n}{i} floor)(m - i lfloor frac{m}{i} floor))
     
     乘法分配律展开,化简,令 (t = min(n, m)) 得:
      ( sum_{i = 1}^n sum_{j = 1}^m (n - i lfloor frac{n}{i} floor)(m - j lfloor frac{m}{j} floor) - sum_{i = 1}^t (n - i lfloor frac{n}{i} floor)(m - i lfloor frac{m}{i} floor))
     (= sum_{i = 1}^n sum_{i = 1}^m nm + msum_{i = 1}^n sum_{i = 1}^m j lfloor frac{n}{i} floor + nsum_{i = 1}^n sum_{i = 1}^m lfloor frac{m}{j} floor +)
     (sum_{i = 1}^n sum_{i = 1}^m ij lfloor frac{n}{i} floor lfloor frac{m}{j} floor - sum_{i = 1}^t nm + m sum_{i = 1}^t i lfloor frac{n}{i} floor - n sum_{i = 1}^t i lfloor frac{m}{i} floor - sum_{i = 1}^t i^2 lfloor frac{n}{i} floor)
     (sum_{i = 1}^n sum_{i = 1}^m ij lfloor frac{n}{i} floor lfloor frac{m}{j} floor) 等于 (sum_{i = 1}^n i lfloor frac{n}{i} floor * sum_{i = 1}^m j lfloor frac{m}{j} floor),一个一个算即可。
     
     代码写的比较长……因为用 (unsigned ll) 为了避免出负数也多了很多取模……

    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    typedef unsigned long long u64;
    
    const u64 mod = 19940417;
    const u64 inv_6 = 3323403;
    
    inline u64 Calc_1(u64 l, u64 r) { return (l + r) * (r - l + 1) / 2 % mod; }
    inline u64 Calc_2(u64 x) { return ((x + 1) * (2 * x + 1) % mod) * (x * inv_6 % mod) % mod; }
    
    int main(int argc, const char *argv[])
    {
      u64 n = 0, m = 0, t = 0, ans = 0, sum_1 = 0, sum_2 = 0;
      scanf("%llu%llu", &n, &m);
      ans = ((n * m % mod) * (n * m % mod) % mod);
      t = min(n, m), ans = (ans + mod - (n * m % mod) * t % mod) % mod;
      for(u64 tmp, l = 1, r = 1; l <= n; l = r + 1) {
        tmp = n / l, r = n / tmp;
        ans = (ans + mod - (Calc_1(l, r) * tmp % mod) * (m * m % mod) % mod) % mod;
        sum_1 = (sum_1 + Calc_1(l, r) * tmp % mod) % mod;
      }
      for(u64 tmp, l = 1, r = 1; l <= m; l = r + 1) {
        tmp = m / l, r = m / tmp;
        ans = (ans + mod - (Calc_1(l, r) * tmp % mod) * (n * n % mod) % mod) % mod;
        sum_2 = (sum_2 + Calc_1(l, r) * tmp % mod) % mod;
      }
      for(u64 tmp, l = 1, r = 1; l <= t; l = r + 1) {
        tmp = n / l, r = min(t, n / tmp);
        ans = (ans + Calc_1(l, r) * (tmp * m % mod)) % mod;
      }
      for(u64 tmp, l = 1, r = 1; l <= t; l = r + 1) {
        tmp = m / l, r = min(t, m / tmp);
        ans = (ans + Calc_1(l, r) * (tmp * n % mod)) % mod;
      }
      for(u64 l = 1, r = 1; l <= t; l = r + 1) {
        r = min(t, min(n / (n / l), m / (m / l)));
        ans = (ans + mod - (mod + Calc_2(r) - Calc_2(l - 1)) * ((n / l) * (m / l) % mod) % mod) % mod;
      }
      printf("%llu
    ", (ans + sum_1 * sum_2) % mod);
    
      return 0;
    }
    
  • 相关阅读:
    斯坦福大学Andrew Ng教授主讲的《机器学习》公开课观后感
    关于内推,你该知道的点点滴滴
    向大学说拜拜——大学 > 兴趣 + 时间 + 思考 + 实践
    源码浅析:InnoDB聚集索引如何定位到数据的物理位置,并从磁盘读取
    5.7.17版本mysqlbinlog实时拉取的二进制日志不完整的原因分析
    InnoDB的ibd数据文件为什么比data_length+index_length+data_free的总和还要大?
    gh-ost工具在线改表过程的详细解析
    MySQL5.7 使用utf8mb4字符集比latin1字符集性能低25%,你敢信?
    通过slow query log可以查出长时间未提交的事务吗?用实验+源码来揭晓答案
    源码浅析:MySQL一条insert操作,会写哪些文件?包括UNDO相关的文件吗?
  • 原文地址:https://www.cnblogs.com/nanjoqin/p/10261968.html
Copyright © 2011-2022 走看看