标签:style color os io for log sp amp on
题意:
给一串数,找出最长的区间使得这个区间里面有个数能被其他所有数整除(包括它自己),求满足这个条件的最长区间的个数及长度,以及这些区间的左端的位置
分析:
这个区间的要求其实就是GCD(ALL)=MIN(ALL),能被其他数整除,这个数肯定是最小的,然后又能被其他数整除(包括自己)这个数就是GCD了
可以二分枚举区间长度,然后验证答案的可靠性
对当前长度的所有区间,套用RMQ,验证是否存在一个区间的GCD=MIN
如果有这样的一个区间,那么说明当前长度可以,加大枚举的区间长度,否则减小
#include<iostream> #include <algorithm> #include <cstdio> #include <vector> #include<cmath> using namespace std; #define MAXN 333333 int N; int gcd(int a,int b){return b==0?a:gcd(b,a%b);} int num[MAXN]; int f1[MAXN][30]; int f2[MAXN][30]; void st(int n) { int i, j, k, m; k = (int) (log((double)n) / log(2.0)); for(i = 0; i < n; i++) { f1[i][0] = num[i]; f2[i][0] = num[i]; } for(j = 1; j <= k; j++) { for(i = 0; i + (1 << j) - 1 < n; i++) { m = i + (1 << (j - 1)); f1[i][j] = min(f1[i][j-1], f1[m][j-1]); f2[i][j] = gcd(f2[i][j-1], f2[m][j-1]); } } } //查询i和j之间的最值,注意i是从0开始的 int rmq_gcd(int i, int j) { int k = (int)(log(double(j-i+1)) / log(2.0)), t2; t2 = gcd(f2[i][k], f2[j - (1<<k) + 1][k]); return t2; } int rmq_min(int i, int j) { int k = (int)(log(double(j-i+1)) / log(2.0)), t1; t1 = min(f1[i][k], f1[j - (1<<k) + 1][k]); return t1; } bool check(int l){ for(int i=0;i<N && i<=N-l;i++){ if(rmq_gcd(i,i+l-1)==rmq_min(i,i+l-1)) return true; } return false; } vector<int>ans; void get(int l){ for(int i=0;i<N && i<=N-l;i++){ if(rmq_gcd(i,i+l-1)==rmq_min(i,i+l-1)) ans.push_back(i+1); } } int main() { #ifndef ONLINE_JUDGE freopen("/home/rainto96/in.txt","r",stdin); #endif int i; scanf("%d", &N); for (i = 0; i < N; i++) { scanf("%d", num+i); } st(N); int l=1,r=N,mid=(l+r)/2+1; while(l<r){ if(check(mid))l=mid; else r=mid-1; mid=(l+r)/2+1; } get(l); cout<<ans.size()<<' '<<l-1<<endl; for(int i=0;i<ans.size();i++){ cout<<ans[i]<<' '; } cout<<endl; return 0; }
CF359D Pair of Numbers [RMQ+ST算法]
标签:style color os io for log sp amp on
原文地址:http://blog.csdn.net/u011775691/article/details/38978855