【题解】[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);
}
}
}

浙公网安备 33010602011771号