Jzoj3895 数字对

给你一个序列s,求出所有最长的区间[l,r]使得存在一个k∈[l,r]且对于任何i∈[l,r]都有s[k]|s[i]

显然如果这个k存在,那么s[k]一定是s[l]~s[r]的最小值

现在问题就成了,求一个最长的区间使得s[l]~s[r]的最小值=s[l]~s[r]的gcd

那么我们可以二分答案,而求一个区间最小和gcd都可以用ST表完成,所以整体复杂度nlg^2n

(虽然说这是solution的方法但是不是最快的方法,最快的方法是枚举k,让后向两边暴力扫描法,复杂度是n^2的但是跑起来非常快!)

正解:313ms

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
inline int Min(int a,int b){ return a<b?a:b; }
inline int gcd(int a,int b){
	for(int c;b;a=b,b=c) c=a%b;
	return a;
}
int preLog[500010],n,w[500010];
vector<int> A;
struct ST_list{
	int (*f)(int,int) ;
	int g[20][500010];
	void init(int* s,int (*f1)(int,int) ){
		f=f1;
		memcpy(g[0]+1,s+1,n<<2);
		for(int i=n;i;--i)
			for(int j=1;i+(1<<j)-1<=n;++j)
				g[j][i]=f(g[j-1][i],g[j-1][i+(1<<j-1)]);
	}
	int query(int l,int r){
		int k=preLog[r-l+1];
		return f(g[k][l],g[k][r-(1<<k)+1]);
	}
} s1,s2;
bool ok(int len){
	int M=n-len;
	for(int i=1;i<=M;++i)
		if(s1.query(i,i+len)==s2.query(i,i+len)) return 1;
	return 0;
}
int main(){
	preLog[1]=0;
	for(int i=2,j=0;i<=500010;++i){
		if(i==(1<<j+1)) ++j;
		preLog[i]=j;
	}
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",w+i);
	s1.init(w,Min); s2.init(w,gcd);
	int l=0,r=n-1;
	for(int m;l<r;){
		m=l+r+1>>1;
		if(ok(m)) l=m;
		else r=m-1; 
	}
	n-=l;
	for(int i=1;i<=n;++i)
		if(s1.query(i,i+l)==s2.query(i,i+l)) A.push_back(i);
	printf("%d %d
",A.size(),l);
	for(int i=0,z=A.size();i<z;++i) printf("%d ",A[i]);
}
暴力:76ms

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 500010
using namespace std;
int a[N],ans[N];
int main()
{
    int n,num=0,val=0;
    cin>>n;
    fo(i,1,n)
    {
             scanf("%d",&a[i]);
             if(a[i]==1)
             {
                        cout<<1<<' '<<n-1<<endl<<1;
                        return 0;
             }
    }
    fo(k,1,n)
    {
             if(a[k]==0) continue;
             int l=k,r=k;
             while(a[l-1]%a[k]==0 && l>1) l--;
             while(a[r+1]%a[k]==0 && r<n) r++;
             if(r-l==val && l!=ans[num]) ans[++num]=l;
             if(r-l>val)
             {
                        fo(i,1,num) ans[i]=0;
                        val=r-l,ans[num=1]=l;
             }
    }
    cout<<num<<' '<<val<<endl;
    fo(i,1,num) printf("%d ",ans[i]);
}

原文地址:https://www.cnblogs.com/Extended-Ash/p/9477339.html