BZOJ4128: Matrix BSGS+矩阵求逆+线性筛
BZOJ4080: [Wf2014]Sensor Network 最大团

BZOJ4052: [Cerc2013]Magical GCD 暴力+RMQ

shinbokuow posted @ Sep 04, 2015 10:58:48 AM in BZOJ with tags rmq 暴力 , 1666 阅读

 

题解:

考虑以某个元素开头的前缀gcd,至多只有log段。

这是因为每一次gcd发生变化必然是原来答案的一个真约数,那么最多只有原来的一半。

所以枚举起点不断二分找出所有段即可。

利用RMQ预处理求区间的gcd,每次可以$O(1)$。

于是时间复杂度$O(nlog^2n)$。

然而事实上,我们直接暴力维护所有段即可,因为每次只需要将末尾添加一个数,且只有log段,暴力判断即可。这样就能做到$O(nlogn)$。

我脑洞也是大了点。。。

代码:

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long ll;
inline ll gcd(ll a,ll b){
	return(!b)?a:gcd(b,a%b);
}

#define N 100010
ll f[N][17];
int len[N];

inline ll query(int l,int r){
	return gcd(f[l][len[r-l+1]],f[r-(1<<len[r-l+1])+1][len[r-l+1]]);
}
int main(){
#ifndef ONLINE_JUDGE
	freopen("tt.in","r",stdin);
#endif
	int T,n,i,j;
	cin>>T;
	for(i=2;i<=100000;++i)
		len[i]=len[i>>1]+1;
	int L,R,mid;
	while(T--){
		scanf("%d",&n);
		for(i=1;i<=n;++i)
			scanf("%lld",&f[i][0]);
		for(j=1;(1<<j)<=n;++j)
			for(i=1;i+(1<<j)-1<=n;++i)
				f[i][j]=gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
		ll ans=0,beg;
		for(i=1;i<=n;++i){
			j=i;
			while(j<=n){
				for(beg=query(i,j),L=j,R=n;L<R;){
					mid=(L+R+1)>>1;
					if(query(i,mid)!=beg)
						R=mid-1;
					else
						L=mid;
				}
				ans=max(ans,beg*(L-i+1));
				j=L+1;
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter