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

sol:
利用分块思想,尽量利用整块的信息查询。

首先只考虑查询。从左往右遍历每个整块,如果 gcd ⁡ ( t m p , t [ i ] . gcd ⁡ ) < t m p \gcd(tmp,t[i].\gcd)<tmp gcd(tmp,t[i].gcd)<tmp 就暴力遍历块内所有元素,否则直接整块查询(用 std::map 暴力即可)。

每次修改就暴力重构块。

我们来分析时间复杂度为什么是对的。根据 gcd ⁡ \gcd gcd 性质不难得出每次 t m p tmp tmp 至少退化成原来的一般,所以暴力遍历的块的个数不超过 log ⁡ a 0 \log{a_0} loga0 次。时间复杂度为 O ( q n ( log ⁡ n + log ⁡ a ) ) O(q\sqrt{n}(\log{\sqrt{n}+\log a)}) O(qn (logn +loga)) 。这个 log ⁡ \log log 实际远小于预期。

总结:本题主要是考虑从询问入手,将 遍历到的 / 重构的 次数尽量控制得小。

#include<bits/stdc++.h> #define db double #define ll long long #define mkp make_pair #define pii pair<int,int> #define inf 0x3f3f3f3f #define fi first #define se second using namespace std; const int Maxn=1e5+5; const int Maxm=320; const int mod=23333333; //如果加上这个块后 gcd 变小了,我们就直接暴力扫整个块 //否则直接在块里面查有没有 xor 为 ? 的数 //每次查询暴力扫到的块不超过 log 个(啊啊啊) inline ll read() { ll x=0,f=1; char c=getchar(); while(c<'0'||c>'9') { c=getchar(); } while(c>='0'&&c<='9') { x=(x<<1)+(x<<3)+c-'0'; c=getchar(); } return x; } int n,m,block,L[Maxn],R[Maxn],bl[Maxn],a[Maxn]; map<ll,int> tong[Maxm]; char op[10]; struct node{ ll gcd,xo; }t[Maxm]; ll gcd(ll x,ll y) { return y==0?x:gcd(y,x%y); } void build(int id) { tong[id].clear(); t[id].gcd=t[id].xo=0; for(int i=L[id];i<=R[id];i++) { t[id].gcd=gcd(t[id].gcd,a[i]); t[id].xo^=a[i]; if(tong[id].find(t[id].xo)==tong[id].end())tong[id][t[id].xo]=i; } } void solve(ll mid) { ll tmp1=0,tmp2=0; for(int i=1;i<=(n-1)/block+1;i++) { if(gcd(tmp1,t[i].gcd)!=tmp1) { for(int j=L[i];j<=R[i];j++) { tmp1=gcd(tmp1,a[j]); tmp2^=a[j]; if(tmp1*tmp2==mid) { printf("%d\n",j-1); return; } } } else { //tmp1 * (tmp2 ^ x) = mid if(mid%tmp1) { tmp2^=t[i].xo; continue; } if(tong[i].find((mid/tmp1)^tmp2)!=tong[i].end()) { printf("%d\n",tong[i][(mid/tmp1)^tmp2]-1); return; } tmp2^=t[i].xo; } } printf("no\n"); return; } signed main() { // freopen("data.in","r",stdin); n=read();block=sqrt(n); for(int i=1;i<=n;i++) { a[i]=read(); bl[i]=(i-1)/block+1; } for(int i=1;i<=(n-1)/block+1;i++) { L[i]=(i-1)*block+1; R[i]=min(n,i*block); build(i); } m=read(); for(int i=1;i<=m;i++) { scanf("%s",op); if(op[0]=='M') { int x=read(),y=read(); x++; a[x]=y; build(bl[x]); } else { ll x=read(); solve(x); } } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530225.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示