首页 > 其他分享 >AGC182 C - Sum of Number of Divisors of Product

AGC182 C - Sum of Number of Divisors of Product

时间:2024-08-12 18:16:45浏览次数:11  
标签:Product 乘积 int Sum AGC182 leq 65 LL mat

题目大意:求长度为1,2,...N,的好序列因数个数。好序列满足每个元素\(1\leq x \leq M\)

\(N \leq 1e18, M \leq 16\)

很容易想到维护所有好序列质因数的指数+1的乘积。
\(\prod b_i, 1 \leq i \leq 6\).

考虑每个数对这个乘积的影响。假设我们只有2, 3, 5这三个质数,序列末端添加15,
乘积从\(b_1 b_2 b_3\) 变成 \(b_1(b_2+1)(b_3+1)=b_1 b_2 b_3 + b_1 b_2 + b_1 b_3 + b_1\)
这样\(b_1 b_2 b_3\) 任意子集的乘积也需要计算。

所有不包含这些质因子的数不会对乘积产生影响,但是会产生方案数, 比如末尾添加7, 乘积保持不变。

每个数对这些乘积会产生什么样的影响呢?用二进制表示是否包含某个因子,我们有111代表\(b_1 b_2 b_3\)乘积,101代表\(b_1 b_3\)乘积 以此类推,用S表示质因子的集合
可以发现如果x包含\(b_2\)(3)这个质因子,任何包含3的集合S都会从去掉3的集合S^(1<<1)转移,系数为质因子的指数。比如\(x=9\), \(b_1(b_2+2)b_3=b_1 b_2 b_3 + 2 b_1 b_3\),
\(x=14\), \((b_1 + 1)b_2 b_3=b_1 b_2 b_3 + b_2 b_3\),对于每一个x,我们都可以得到一个转移矩阵。把所有转移矩阵相加,再利用矩阵快速幂,就可以求得最终的答案。

这样转移系数就满足加法原理,比如末尾的两个选择,9, 15. \(b_1 b_2 b_3\)乘积的变化就是
$b_1(b_2+2)b_3 + b_1 (b_2 + 1) (b_3 + 1) =(b_1 b_2 b_3 + 2 b_1 b_3) + (b_1 b_2 b_3 + b_1 b_3 + b_1 b_2 + b_1) = 2 b_1 b_2 b_3 + 3 b_1 b_3 + b_1 b_2 + b_1 $,

即,枚举1到m,每个数包含3的因子的个数和就是 每个包含3的集合S都会从去掉3的集合S^(1<<1)转移的系数。
对于上述类似\(b_1 b_2 b_3\)从\(b_1\)转移的系数,我们要指数的乘积, 比如末端是\(12=2^2 * 3^1\),\(b_1\)的系数是\(2 * 1\)
这样求出末端添加x的转移系数后, 枚举S的子集得到dp的转移矩阵系数。

空集代表的意义是有多少个序列。比如末端填3, \((b_2 + 1) = b_2 + 1\). 这里对上一次操作的所有序列都要+1.
矩阵快速幂求前缀和,再添加一行\((0, 0, 0, ..., 1, 1)\)。注意算n+1次才能得到前n个的和。还要消除第0次求和的影响。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int mod = 998244353;
int prime[7] = {2, 3, 5, 7, 11, 13};
const int NUM_P = 6;
LL mat[65][65], base[65][65], res[65][65], lala[65][65];
LL coef[65];
void mat_mul(LL A[][65], LL B[][65], LL C[][65]){
  for(int i = 0;i <= 64; i++){
    for(int j = 0;j <= 64; j++){
      LL tmp = 0;
      for(int k = 0;k <= 64; k++){
        (tmp += B[i][k] * C[k][j] % mod) %= mod;
      }
      lala[i][j] = tmp;
    }
  }
  for(int i = 0;i <= 64; i++){
    for(int j = 0;j <= 64; j++){
      A[i][j] = lala[i][j];
    }
  }
}
void ksm(LL x){
  for(int i = 0;i <= 1 << NUM_P; i++)base[i][i] = res[i][i] = 1;
  mat_mul(base, base, mat);
  while(x){
    if(x & 1){
      mat_mul(res, res, base);
    }
    mat_mul(base, base, base);
    x >>= 1;
  }
  for(int i = 0;i <= 64; i++){
    for(int j = 0;j <= 64; j++)
      mat[i][j] = res[i][j];
  }
}
int main(){
  LL n;
  int m;
  cin>>n>>m;
  for(int i = 0;i < 1 << NUM_P; i++){
    for(int j = 1;j <= m; j++){
      int add = 1;
      for(int k = 0;k < NUM_P; k++){
        if(!((i >> k) & 1))continue;
        int tmp = j;
        int cnt = 0;
        while(tmp % prime[k] == 0){
          tmp /= prime[k];
          cnt++;
        }
        add *= cnt;
      }
      coef[i] += add;
    }
  }
  for(int i = 0;i < 1 << NUM_P; i++){
    for(int s = i;s > 0;s = (s - 1) & i){
      mat[i][i^s] += coef[s];
    }
    mat[i][i] += coef[0];
  }
  mat[1<<NUM_P][1<<NUM_P]++;
  mat[1<<NUM_P][(1<<NUM_P)-1]++;
  ksm(n + 1);
  int res = 0;
  for(int i = 0;i < 1 << NUM_P; i++){
    (res += mat[1<<NUM_P][i]) %= mod;
  }
  cout<<(res - 1 + mod) % mod<<endl;
  return 0;
}

标签:Product,乘积,int,Sum,AGC182,leq,65,LL,mat
From: https://www.cnblogs.com/dqk2003/p/18355498

相关文章

  • 题解:AT_abc351_f [ABC351F] Double Sum
    关于某c人士强制偷袭代码导致AT号被封,\({\color{red}\mathrm{警钟敲碎}}\)。题意一个长\(n\)的数组\(a\),求所有顺序对中两元素之差的和。分析听说有大佬2min切掉。很明显,暴力过不去。考虑计算每个元素的贡献。设\(id\)为该元素之前所有比它小的元素个数,\(sum\)表示这些......
  • 爱因斯坦求和约定einsum简单例题解读
    概论在爱因斯坦求和约定或einsum()格式字符串中,所有的索引都可以分为两类:自由索引集和求和索引集。它们的区别很简单:自由索引是用于输出规范中的索引。它们与外层for循环相关联。求和索引是所有其他索引:它们出现在参数规范中,但不出现在输出规范中。之所以称为求和索引,是因......
  • 举例说明二次型和用 einsum 计算
    什么是“二次型”在数学中,特别是线性代数中,二次型(quadraticform)是一个涉及向量和矩阵的表达式,其形式为:[Q(v)=v^TMv]其中:(v)是一个向量(长度为(n))。(M)是一个(n\timesn)的方阵(矩阵)。(v^T)表示向量(v)的转置(即一个列向量变为行向量)。这个表达......
  • [ABC366D] Cuboid Sum Query 题解
    [ABC366D]CuboidSumQuery题解原题传送门AT原题传送门题意翻译:给予一个\(N\timesN\timesN\)的三维矩阵,有\(Q\)次询问,对于每次询问,给与四个数,分别为\(L_1,R_1,L_2,R_2,L_3,R_3\)求在三维矩阵中\(a[L_1][L_2][L_3]\)到\(a[R_1][R_2][R_3]\)的区间和。三维前缀......
  • IT基础书籍汇集_sum
    希望STUDENT过软考,所以有些基础书籍还是需要看看--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------虽然书籍,标注“著”的书籍一般......
  • Python - sum()
     >>>bugs=["bug1","bug2"]>>>sum(bugs,[])Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:canonlyconcatenatelist(not"str")tolist>&g......
  • Range Minimum Sum
    非常经典的删数问题,见这篇题解我赛时的时候考虑的时候删除了\(a_i\)后,有哪些区间会被删除,哪些区间会被加入删除的区间:最小值是\(a_i\)的区间(\(O(1)\)计算)、\(a_i\)作为一个端点但是\(a_i\)不是最小值的区间(差分维护)加入的区间:左端点属于\((l_i,i)\)且右端点属于\((i,r_i)\)的区......
  • D - Xor Sum 2
    原题链接题解异或就是不进位的加法,所以区间内,每一位最多只有一个一暴力方法:遍历每一位区间,查看异或和加和\(O(n^3)\)前缀和优化:找每个右端点合法的左端点\(O(n^2)\)利用性质优化:由于最多只有一个1,所以这样的左端点不会随着右端点的递增而递增\(O(n)\)code#include<bi......
  • B - Minimum Sum
    原题链接题解\(O(n^3)\)的暴力方法:遍历所有区间,然后找出每个区间内的最小值\(O(n^2)\)的暴力方法:考虑每个点的贡献,往左扩展直至出现比其小,往右扩展直至出现比其小的观察\(O(n^2)\)的暴力方法,我们发现往左扩展和往右扩展相互独立所以我们只观察往左扩展”往左扩展直至......
  • 在 SQL 中,怎样使用聚合函数(如 SUM、AVG、COUNT 等)来计算数据的总和、平均值和数量?
    在SQL中,可以使用聚合函数来计算数据的总和、平均值和数量。以下是一些常用的聚合函数的示例:SUM函数:计算指定列的总和。SELECTSUM(column_name)FROMtable_name;AVG函数:计算指定列的平均值。SELECTAVG(column_name)FROMtable_name;COUNT函数:计算指定列的数......