错题-旅途不止

旅途不止

用差分数组!!!

题目大意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2wS2vG8F-1657099673678)(C:\Users\YYYYYKN\AppData\Roaming\Typora\typora-user-images\image-20220502235853351.png)]

样例输入

5
3
1 4 3 2
2 4 2 2 
3 5 6 1 

样例输出

3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zvfpblXr-1657099673680)(C:\Users\YYYYYKN\AppData\Roaming\Typora\typora-user-images\image-20220502235912673.png)]

解法

​ 在计算幂次的时候要使用快速幂进行计算。在对区间 [ l , r ] [l,r] [l,r] 的数都乘上一个数 c b c^b cb 的操作中,要使用差分数组,因为对差分数组的单个元素(如下标 a )的加和另一个元素(如下标 b )的减就相当于对整个原数组进行一整段 [ a , b ) [a,b) [a,b) 区间的加和,然后就不需要对区间 [ l , r ] [l,r] [l,r] 每一个数字都去做乘法,复杂度就会降低。例如本题,就可以在差分数组[L] += b 并且 差分数组[r + 1] -= b;这是由差分数组的性质决定的。可以发现数据范围中底数是小于等于 100 的,因此可以只对底数 c 进行质因数分解,并且分解出的质数不会超过 100 以内的那 25 个质数,然后在记录幂次的差分数组上一次性加上 b 。这是因为对 c b c^b cb 质因数分解,等同于对一个 c 质因数分解然后再在每个分解出的质数的幂次上加上 b 。计算每一个质数的最小幂次,再以质数为底,以最小幂次为指数相乘即为最大公约数。

时间复杂度

O ( m a x ( m , n ) ) O(max(m,n)) O(max(m,n))

​ 在计算快速幂的函数的时间复杂度为 O ( log ⁡ b ) O(\log{b}) O(logb) 。在进行 m 次操作中,最外层时间复杂度为 O ( m ) O(m) O(m) ;在进行对每一个底数 c 质因数分解的操作中时间复杂度为 O ( 1 ) O(1) O(1) ,因次在对区间进行相乘的操作的时间复杂度为 O ( m ) O(m) O(m)

​ 在记录 100 以内的每一个质数的最小幂次的操作的时间复杂度为 O ( n ) O(n) O(n)

​ 综上,本题时间复杂度为 O ( m a x ( m , n ) ) O(max(m,n)) O(max(m,n))

代码
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll mod = 1e9 + 7;
const ll zhishu[25] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};

ll zhiyinshufenjie[2000000][26] = {0};
ll kuaisumi(ll c, ll b)
{
     ll result = 1;
     while (b != 0)
     {
          if (b % 2 == 1)
               result = result * c % mod; //涉及取模运算的题目中,往往中间过程的结果会超出int或long long的范围。需要使用取模来避免出现错误
         //但是在这题中还来不及取模,在result * c就已经超过long long的范围了,因此不能直接计算出乘数,需要再换个方法
          c = c * c % mod;
          b >>= 1;
     }
     return result;
}
int main()
{
     ll n, m;
     cin >> n >> m;

     //开始操作
     for (ll i = 1; i <= m; i++)
     {
          ll l, r, c, b;
          cin >> l >> r >> c >> b;
          //ll chengshu = kuaisumi(c, b);//注意这里,数据太庞大可能在计算快速幂的模块里等不到求模就已经超限了,因此不能用这个办法去算

          //可以发现数据范围中底数是小于等于100的,因此可以只对底数c进行质因数分解,然后在幂次上一次性加上b。这是因为对c^b质因数分解,等同于对一个c质因数分解然后再在每个分解出的质数的幂次上加上b

          //这里要用到差分数组,因为对差分数组的单个元素的加就相当于对整个原数组进行一整段区间的加和,然后就不需要对l-r每一个数字都去做乘法,复杂度就会降低。例如本题,就可以在
         //差分数组[l] += b 并且 差分数组[r + 1] -= b;这是由差分数组的性质决定的
         
          //把每一个数字的质因数分解的质数的幂次作为差分数组
          //对一个区间的每一个数字乘上同一个数字就是这个乘数对应的所有质因数分解后的质数的幂次都加上分解后的质数的幂次,就是差分数组在一个区间都把所有的数字加上k
          for (ll j = 0; j < 25; j++)
          {
               if (c >= zhishu[j])
               {
                    while (c % zhishu[j] == 0)
                    {
                         zhiyinshufenjie[l][j]+=b;
                         zhiyinshufenjie[r + 1][j]-=b;
                         c /= zhishu[j];
                    }
               }
          }
     }

    
    
     ll zuixiaomici[25] = {0}; //记录100以内的每一个质数的最小幂次,再以质数为底,以最小幂次为指数相乘即为最大公约数
     for (ll i = 0; i < 25; i++)
     {
          zuixiaomici[i] = zhiyinshufenjie[1][i];
          for (ll j = 2; j <= n; j++)
          {
               zhiyinshufenjie[j][i] += zhiyinshufenjie[j - 1][i];
               zuixiaomici[i] = min(zuixiaomici[i], zhiyinshufenjie[j][i]);
          }
     }

     ll zuidagongyueshu = 1;
     for (int i = 0; i < 25; i++)
     {
          zuidagongyueshu = zuidagongyueshu * kuaisumi(zhishu[i], zuixiaomici[i]) % mod;
     }
     cout << zuidagongyueshu;
     return 0;
}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值