[BZOJ4028][HAOI2015]公约数数列[分块+分析暴力]

题意

题目链接

分析

  • 首先明确 \(xor\) 运算和 \(\rm gcd\) 没有联系!

  • 注意到一个数字取 \(\rm gcd\) 且保证每次取 \(\rm gcd\) 值都会变小的话,最多取 \(\log\) 次。
    比较显然,如果每次都变小的话至少都除以了因子 \(2\) ,变为原来的二分之一。

  • 所以考虑一个暴力分块,记录每一块的 \(\rm gcd\) G[i]、异或和X[i]、前缀异或和。

  • 如果 \({\rm gcd}(lastgcd,G[i])=lastgcd\) ,那么直接在该块记录的前缀异或和中查找\(\frac{val}{lastgcd}\ {\rm xor}\ lastxorv\) 的最小的值即可。

  • 总时间复杂度为 \(O(n\log n \sqrt n)\)

重点:\(\rm gcd\) 的取值次数最多有 \(\log\) 次变化!

代码

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch))	{if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
	return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
typedef pair<LL,int> pii;
const int N=1e5 + 7;
int n,sz;
int bl[N],a[N],G[N],X[N];
char s[N];
vector<pii>v[400];
int gcd(int a,int b){
	return !b?a:gcd(b,a%b);
}
void build(int z){
	X[z]=0;v[z].clear();
	rep(i, sz*(z-1)+1, min(sz*z,n)){
		v[z].pb(make_pair(X[z]^=a[i],i));
		G[z]=i==(sz*(z-1)+1)?a[i]:gcd(G[z],a[i]);
	}
	sort(v[z].begin(),v[z].end());
}
int query(LL val){
	int lastg=a[1],lastx=0;
	rep(i,1,sz){
		lastg=i==1?a[1]:gcd(lastg,a[i]),lastx^=a[i];
		if(1ll*lastg*lastx==val) return i;
	}
	rep(z,2,bl[n]){
		if(gcd(lastg,G[z])==lastg){
			LL to=(val/lastg)^lastx;lastx^=X[z];
			if(val%lastg) continue;
			int x=lower_bound(v[z].begin(),v[z].end(),make_pair(to,0))-v[z].begin();
			if(x==v[z].size())  continue;
			pii tmp=v[z][x];
			if(tmp.first==to) return tmp.second;
		}
		else rep(i,sz*(z-1)+1,min(sz*z,n)){
			lastg=gcd(lastg,a[i]),lastx^=a[i];
			if(1ll*lastg*lastx==val) return i;
		}
	}
	return 0;
}
int main(){
	n=gi();sz=sqrt(n);
	rep(i,1,n) a[i]=gi(),bl[i]=(i-1)/sz+1;
	rep(z,1,bl[n]) build(z);
	
	int q=gi();
	int x;LL y;
	rep(i,1,q){
		scanf("%s",s);
		if(s[0]=='M') {
			x=gi()+1,y=gi();
			a[x]=y,build(bl[x]);
		}else{
			scanf("%lld",&y);
			int res=query(y)-1;
			if(res==-1) puts("no");
			else printf("%d\n",res);
		}
	}
	return 0;
}
posted @ 2018-10-16 19:43  fwat  阅读(147)  评论(0编辑  收藏  举报