首页 > 其他分享 >题解 P4108【[HEOI2015]公约数数列】

题解 P4108【[HEOI2015]公约数数列】

时间:2023-06-20 20:13:28浏览次数:50  
标签:gcd P4108 题解 ll pos tot HEOI2015 bxor operatorname

看到这种奇怪的操作,首先想到分块。

以下记值域为 \(w\),块长为 \(B\)。

前缀 \(\gcd\) 显然单调不增,而且后一个必须是前一个的因数,如果变化至少要减半。因此,我们知道,共有 \(\mathcal O(\log w)\) 个不同的前缀 \(\gcd\)。我们可以接受对这些块暴力,只需要对前缀 \(\gcd\) 都相同的块能快速求答案即可。

有以上思路做铺垫,容易想到设 \(\operatorname{l}(x)\) 为第 \(x\) 块的左端点(含),\(\operatorname{r}(x)\) 为第 \(x\) 块的右端点(含),\(\operatorname{pos}(i)\) 为第 \(i\) 个数所在块,\(\operatorname{bgcd}(x)\) 为第 \(x\) 块的 \(\gcd\),\(\operatorname{bxor}(i)\) 表示区间 \([\operatorname{l}(\operatorname{pos}(i)),i]\) 的异或和。同时,我们对每个块维护一个 map \(\operatorname{bfirst}\),表示这个块内每个值作为 \(\operatorname{bxor}\) 第一次出现的位置。

对于查询 \(x\) 操作,从前往后扫描每个块,维护当前 \(\gcd\) 和异或和。利用 \(\operatorname{bgcd}\) 容易判断这个块内前缀 \(\gcd\) 是否发生变化。如果发生变化,我们暴力整个块检查;如果未发生变化,即求 \(\operatorname{bfirst}(\frac{x}{g}\oplus s)\),其中 \(g,s\) 为此前所有块的 \(\gcd\) 和异或和。暴力检查的块数为 \(\mathcal O(\log w)\),这部分复杂度 \(\mathcal O(B\log^2w)\)(另一只 \(\log\) 是求 \(\gcd\));其他块的复杂度为 \(\mathcal O(\frac{n}{B}\log B)\)。

对于单点修改操作,暴力改所在块即可。复杂度 \(\mathcal O(B\log B)\)。

取 \(B=\sqrt{n}\),总复杂度 \(\mathcal O(n\log n+q\sqrt{n}\log^2w)\)。

//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x,y,z) for(ll x=(y);x<=(z);x++)
#define per(x,y,z) for(ll x=(y);x>=(z);x--)
#define debug(format...) fprintf(stderr, format)
#define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false)
using namespace std;
typedef long long ll;

mt19937 rnd(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
ll randint(ll L, ll R) {
    uniform_int_distribution<ll> dist(L, R);
    return dist(rnd);
}

template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}

const ll N = 1e5+5, BS = 505;

ll n, a[N], q, L[BS], R[BS], pos[N], B, tot, bgcd[BS], bxor[N];
map<ll, ll> bfirst[BS];

void init() {
    B = sqrt(n);
    chkmin(B, n);
    chkmax(B, 1LL);
    while(++tot) {
        L[tot] = R[tot-1] + 1;
        R[tot] = min(tot*B, n);
        rep(i, L[tot], R[tot]) {
            pos[i] = tot;
            bgcd[tot] = __gcd(bgcd[tot], a[i]);
            bxor[i] = (i == L[tot] ? 0 : bxor[i-1]) ^ a[i];
            if(!bfirst[tot].count(bxor[i])) bfirst[tot][bxor[i]] = i;
        }
        if(R[tot] == n) break;
    }
}

void modify(ll p, ll k) {
    a[p] = k;
    bgcd[pos[p]] = 0;
    map<ll, ll>().swap(bfirst[pos[p]]);
    rep(i, L[pos[p]], R[pos[p]]) {
        bgcd[pos[p]] = __gcd(bgcd[pos[p]], a[i]);
        bxor[i] = (i == L[pos[p]] ? 0 : bxor[i-1]) ^ a[i];
        if(!bfirst[pos[p]].count(bxor[i])) bfirst[pos[p]][bxor[i]] = i;
    }
}

ll query(ll x) {
    ll gcd = 0, now = 0;
    rep(i, 1, tot) {
        if(gcd != __gcd(gcd, bgcd[i])) {
            rep(j, L[i], R[i]) {
                gcd = __gcd(gcd, a[j]);
                now ^= a[j];
                if(gcd * now == x) return j;
            }
        }
        else {
            if(x % gcd == 0 && bfirst[i].count((x/gcd)^now)) return bfirst[i][(x/gcd)^now];
            now ^= bxor[R[i]];
        }
    }
    return -1;
}

int main() {
    scanf("%lld", &n);
    rep(i, 1, n) scanf("%lld", &a[i]);
    init();
    for(scanf("%lld", &q); q; q--) {
        char op[8];
        scanf("%s", op);
        if(op[0] == 'M') {
            ll p, k;
            scanf("%lld%lld", &p, &k);
            modify(p+1, k);
        }
        else {
            ll x;
            scanf("%lld", &x);
            ll ans = query(x);
            if(ans == -1) puts("no");
            else printf("%lld\n", ans-1);
        }
    }
    return 0;
}

标签:gcd,P4108,题解,ll,pos,tot,HEOI2015,bxor,operatorname
From: https://www.cnblogs.com/ruierqwq/p/LG-P4108.html

相关文章

  • uni-app微信小程序路由传参数据截断问题解决
    跳转页面:因为数据接受页面是富文本编辑器接收,所以先是将数据双引号处理了。数据太多太长,跳转页面只要用encodeURIComponent()函数将其数据处理后传过去constdetails=this.oneform.text.replace(/"/g,'\'')this.$tab.navigateTo(`/pages/common/editor/editor?details=${e......
  • 我是如何写题解的
    在算法竞赛中,写题解是我们不可或缺的一部分。它不仅能够帮助我们整理思路、总结经验,还可以与他人分享我们的解题思路和代码实现。然而,写一篇较完备的题解往往非常繁琐,需要手动复制粘贴题目链接、题号和AC代码,这不仅费时费力,还容易分散我们的注意力,因为我们写题解的核心内容是对题......
  • 【问题解决】 网关代理Nginx 301暴露自身端口号
    一般项目上常用Nginx做负载均衡和静态资源服务器,本案例中项目上使用Nginx作为静态资源服务器出现了很奇怪的现象,我们一起来看看。“诡异”的现象部署架构如下图,Nginx作为静态资源服务器监听8080端口,客户浏览器通过API网关的443端口(就是https)获取Nginx静态资源。现象是用户浏览......
  • react经典面试题解析--持续更新--day02
    二十一、高阶组件的使用场景1、数据获取:高阶组件可以在组件挂载时自动获取数据,并将数据通过props传递给被包装组件。2、权限控制:高阶组件可以检查用户是否有访问该组件的权限,从而决定是否渲染该组件。3、代码重用:高阶组件可以通过封装一些常见的逻辑,来提高代码的复用性。4、......
  • VONE客户端常见问题解决方案
    一、连接服务器失败打开vone客户端时,提示“连接服务器失败,请确认网络连接是否正常”,如下图:![image](https://img2023.cnblogs.com/blog/1224277/202306/1224277-20230620102849617-1673950342.png)![image](https://img2023.cnblogs.com/blog/1224277/202306/1224277-20230......
  • 题解 CF1840D【Wooden Toy Festival】
    不妨设\(a\)单调递增(无重复),显然如果\(n\le3\)答案就是\(0\)。显然答案\(k\)具有可二分性。也就是说,当\(k<k_0\)时一定不存在合法的\(x,y,z\),当\(k\gek_0\)时一定存在,\(k_0\)就是答案。因此二分答案,只需要验证答案\(k\)是否存在合法的\(x,y,z\)。为了覆盖到......
  • Codeforces Round 879 (Div. 2) 题解
    寄!大!了!Rating-=124.(恼)https://codeforces.com/contest/1834C.GamewithReversing发现\(\text{rev}(S)\toS\)和\(\text{rev}(T)\toT\)本质上是一样的。赛时就一个劲的对着\(S\)操作,,,。我们考虑单点修改在\(S\)上做,翻转操作在\(T\)上做。设\(\displaysty......
  • [ABC216G] 01Sequence 题解
    01Sequence题目大意构造一个满足\(m\)个形如\((l,r,x)\)的限制条件的\(01\)序列,其中\((l,r,x)\)表示区间\([l,r]\)的和不小于\(x\),你需要保证序列中\(1\)的个数最小。思路分析贪心的想,如果我们将限制按右端点排序,那么当遍历到一个区间,发现现有的和不满足限制条件......
  • 题解:【AT Educational DP Contest-O】 Matching
    题目链接来点位运算优化,目前也是拿下了洛谷最优解,比第二名快一倍:#include<bits/stdc++.h>#defineintlonglong#definebtp(x)__builtin_popcount(x)#definelowbit(x)((x)&(-x))usingnamespacestd;namespaceFastIO{template<typenameT=int>inlineTread()......
  • SecureCRT连接慢的问题解决
    选定SSH2,选择Authentication,勾选Password,然后将该选项上移,挪到第一位即可 修改SecureCRT配置目录(C:\Users\manager\AppData\Roaming\VanDyke\Config\)的Sessions子目录下对应的服务器ini配置文件,GSSAPIMethod设置的值为none,重启SecureCRT,连接贼快   原贴:1、https:/......