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

题意

题目链接

分析

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

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

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

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

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

重点:( m 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
",res);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/yqgAKIOI/p/9800196.html