Link
Diffculty
算法难度5,思维难度7,代码难度6
Description
给定长度为 n n n的序列,要求支持两种操作,共 q q q个:
- 给定 i d , v id,v id,v,将 i d id id位置的值修改成 v v v
- 给定 x x x,求最小正整数 p p p使得 g c d ( a 1 , a 2 , . . . , a p ) × x o r ( a 1 , a 2 , . . . , a p ) = x gcd(a_1,a_2,...,a_p)\times xor(a_1,a_2,...,a_p)=x gcd(a1,a2,...,ap)×xor(a1,a2,...,ap)=x
1 ≤ n ≤ 1 0 5 , 1 ≤ q ≤ 1 0 4 1\le n\le 10^5,1\le q\le 10^4 1≤n≤105,1≤q≤104
Solution
神仙题,不会不会。
g c d gcd gcd有个性质,就是前缀 g c d gcd gcd一定是单调不升的,这个很重要,我们可以在这个基础上分块。
我们对序列分块之后,记 f 1 ( i ) f1(i) f1(i)为从块头到 i i i的前缀 g c d gcd gcd, f 2 ( i ) f2(i) f2(i)为从块头到 i i i的前缀 x o r xor xor。
修改就暴力重构这个块。
查询我们一个块一个块处理,我们考虑之前所有块的前缀 g c d gcd gcd和加上这个块的前缀 g c d gcd gcd是否相等。
我们记前面所有块的 g c d gcd gcd为 l a s t g c d lastgcd lastgcd,所有块的 x o r xor xor为 l a s t x o r lastxor lastxor
如果相等,那么我们可以直接在块内找是否存在一个 f 2 ( i ) = x l a s t g c d xor l a s t x o r f2(i)=\frac x {lastgcd} \operatorname{xor}lastxor f2(i)=lastgcdxxorlastxor
这个东西可以预处理和修改的时候每个块都维护一个 m a p map map,就能快速查询了。
如果不相等,那么暴力枚举块内每个位置,直接判断。
这样子复杂度就是 O ( q n l o g n ) O(q\sqrt n logn) O(qnlogn)了,因为每次变化 g c d gcd gcd至少减少一半,所以不相等的最多 l o g n logn logn次。
代码注意一下细节就好了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#define LL long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=x*10+(ch^48),ch=getchar();
return f==1?x:-x;
}
inline LL readLL(){
LL x=0;int f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=x*10LL+(ch^48),ch=getchar();
return f==1?x:-x;
}
const int N=1e5+5,sqN=320;
map<LL,int> mp[sqN];
int n,a[N],q,block,cnt,belong[N],L[N],R[N],f1[N],f2[N];
inline LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int main(){
n=read();
for(int i=1;i<=n;++i)a[i]=read();
block=sqrt(n);
cnt=n/block;
if(n%block)cnt++;
for(int i=1;i<=n;++i)belong[i]=(i-1)/block+1;
for(int i=1;i<=cnt;++i)L[i]=(i-1)*block+1,R[i]=i*block;
R[cnt]=n;
for(int i=1;i<=cnt;++i){
f1[L[i]]=a[L[i]];
f2[L[i]]=a[L[i]];
mp[i][f2[L[i]]]=L[i];
for(int j=L[i]+1;j<=R[i];++j){
f1[j]=gcd(f1[j-1],a[j]);
f2[j]=f2[j-1]^a[j];
if(!mp[i][f2[j]])mp[i][f2[j]]=j;
}
}
q=read();
for(int s=1;s<=q;++s){
char ch[10];
scanf("%s",ch+1);
if(ch[1]=='M'){
int x=read()+1,v=read();
a[x]=v;
int i=belong[x];
mp[i].clear();
f1[L[i]]=a[L[i]];
f2[L[i]]=a[L[i]];
mp[i][f2[L[i]]]=L[i];
for(int j=L[i]+1;j<=R[i];++j){
f1[j]=gcd(f1[j-1],a[j]);
f2[j]=f2[j-1]^a[j];
if(!mp[i][f2[j]])mp[i][f2[j]]=j;
}
}
else{
LL x=readLL();int flag=0;
LL lastgcd,lastxor;
for(int i=1;i<=R[1];++i){
if((LL)f1[i]*f2[i]==x){
flag=1;
printf("%d\n",i-1);
break;
}
}
if(flag)continue;
lastgcd=f1[R[1]];
lastxor=f2[R[1]];
for(int i=2;i<=cnt;++i){
int nowgcd=gcd(lastgcd,f1[R[i]]);
if(nowgcd==lastgcd){
if(x%nowgcd){
lastxor^=f2[R[i]];
continue;
}
int num=mp[i][(LL)(x/nowgcd)^lastxor];
if(num){
flag=1;
printf("%d\n",num-1);
break;
}
lastxor^=f2[R[i]];
}
else{
for(int j=L[i];j<=R[i];++j){
lastgcd=gcd(lastgcd,a[j]);
lastxor^=a[j];
if(lastgcd*lastxor==x){
flag=1;
printf("%d\n",j-1);
break;
}
}
if(flag)break;
}
}
if(flag)continue;
else printf("no\n");
}
}
return 0;
}