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)的主要内容,如果未能解决你的问题,请参考以下文章

牛客练习赛100E.小红的公倍数(线段树+究极卡常

牛客练习赛100E.小红的公倍数(线段树+究极卡常

牛客练习赛100E.小红的公倍数(线段树+究极卡常

棋盘划分问题中4的k次方减一是三的倍数

2022-07-27:小红拿到了一个长度为N的数组arr,她准备只进行一次修改, 可以将数组中任意一个数arr[i],修改为不大于P的正数(修改后的数必须和原数不同), 并使得所有数之和为X的倍数。

小红的删数字(博弈)