旅途不止
用差分数组!!!
题目大意
样例输入
5
3
1 4 3 2
2 4 2 2
3 5 6 1
样例输出
3
解法
在计算幂次的时候要使用快速幂进行计算。在对区间 [l,r][l,r][l,r] 的数都乘上一个数 cbc^bcb 的操作中,要使用差分数组,因为对差分数组的单个元素(如下标 a )的加和另一个元素(如下标 b )的减就相当于对整个原数组进行一整段 [a,b)[a,b)[a,b) 区间的加和,然后就不需要对区间 [l,r][l,r][l,r] 每一个数字都去做乘法,复杂度就会降低。例如本题,就可以在差分数组[L] += b 并且 差分数组[r + 1] -= b;这是由差分数组的性质决定的。可以发现数据范围中底数是小于等于 100 的,因此可以只对底数 c 进行质因数分解,并且分解出的质数不会超过 100 以内的那 25 个质数,然后在记录幂次的差分数组上一次性加上 b 。这是因为对 cbc^bcb 质因数分解,等同于对一个 c 质因数分解然后再在每个分解出的质数的幂次上加上 b 。计算每一个质数的最小幂次,再以质数为底,以最小幂次为指数相乘即为最大公约数。
时间复杂度
O(max(m,n))O(max(m,n))O(max(m,n))
在计算快速幂的函数的时间复杂度为 O(logb)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(max(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;
}