E.小红的公倍数(set)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了E.小红的公倍数(set)相关的知识,希望对你有一定的参考价值。
E.小红的公倍数(set)
区间合并,线性筛预处理每个数的最小质因子和 d p ( i , j ) dp(i,j) dp(i,j) 质数i的 j j j次方。
每次对于区间 [ l , r ] [l,r] [l,r] 先分裂包含位置 l l l和 r r r的区间,然后再合并。
时间复杂度: O ( n l o g l o g n × k ) O(nloglogn\\times k) O(nloglogn×k)
#pragma GCC optimize("Ofast","inline")
#pragma GCC optimize(2)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <math.h>
#include <map>
#include <set>
#include <queue>
#include "unordered_map"
using namespace std;
#define endl '\\n'
const int maxn = 2e4 + 5;
const int mod = 1e9 + 7;
long long qb[maxn][21];
int a[maxn],n,m,nxt[maxn];
struct node
int l, r;
unordered_map<int,int> mp;
mutable long long v;
bool operator <(const node &a) const
return l < a.l;
;
set <node> s;
set<node>::iterator split(int pl)
auto it = --s.upper_bound(pl);
if(it->l == pl) return it;
int l = (*it).l, r = (*it).r,v = (*it).v;
unordered_map<int,int> mp = (*it).mp;
s.erase(it); s.insert((node)l, pl - 1,mp,v);
return s.insert((node)pl, r,mp,v).first;
inline int max(int a,int b)
return a > b ? a : b;
//提取区间一定要先分裂右边再分裂左边,不然可能你到到时分裂的后边已经是被删除的,然后就会报错
long long assign(int l, int r)
auto it = s.upper_bound(l);
it --;
if (it->r >= r)
return it->v;
auto itr = split(r + 1), itl = split(l);
auto resl = itl,resr = itr;
unordered_map<int,int> p;
for(auto it = itl;it != itr;it ++) //这里如果先分裂左边 右边可能是已经是删除的找不到了
for(auto k : it->mp)
p[k.first] = max(k.second,p[k.first]);
long long x = 1;
for(auto k : p)
x = x * qb[k.first][k.second] % mod;
while (itl != s.begin() && prev(itl)->v == x)--itl;
while (itr->v == x)++itr;
int ll = itl->l, rr = itr->l - 1;
s.erase(itl,itr);
s.insert((node)ll,rr,p,x);
return x;
void solve()
cin >> n >> m;
for (int i = 1; i <= maxn - 2; ++i)
qb[i][0] = 1;
for (int j = 1; j <= 20; ++j)
qb[i][j] = qb[i][j - 1] * i % mod;
for (int i = 1; i <= n; ++i)
cin >> a[i];
unordered_map<int,int> mp;
while (a[i] > 1)
int cur = nxt[a[i]];
int ans = 0;
while (nxt[a[i]] == cur) ans ++,a[i] /= cur;
mp[cur] = ans;
s.insert(i,i,mp,a[i]);
s.insert(n+1,n+1);
while (m --)
int l,r;
cin >> l >> r;
cout << assign(l,r) << endl;
signed main()
std::ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int t = 1;
for (int i = 2; i < maxn; ++i)
if (nxt[i] == 0)
nxt[i] = i;
qb[i][0] = 1;
for (int j = 1; j <= 20; ++j) qb[i][j] = 1ll * qb[i][j - 1] * i % mod;
if (i > 10000) continue;
for (int j = i * i; j < maxn; j += i)
if (nxt[j] == 0) nxt[j] = i;
// cin >> t;
while (t--) solve();
以上是关于E.小红的公倍数(set)的主要内容,如果未能解决你的问题,请参考以下文章
2022-07-27:小红拿到了一个长度为N的数组arr,她准备只进行一次修改, 可以将数组中任意一个数arr[i],修改为不大于P的正数(修改后的数必须和原数不同), 并使得所有数之和为X的倍数。