原题链接:http://codeforces.com/problemset/problem/359/D
思路:首先对符合题目的长度(r-l)从0到n-1进行二分查找,对每一个长度进行check,看是否满足条件。
满足条件的话需要区间【l,r】内的最小值和最大公约数相等,如果暴力搜索,会超时,故采用st(sparse table)算法,建立table只需要O(nlgn)时间,查询是O(1),远远小于暴力搜索
st算法具体可参考http://baike.baidu.com/view/1536346.htm#2,只要适用于一段区间内的最大最小等值的计算。
AC代码如下:
#include <iostream> #include <cstdio> #include <iomanip> #include <algorithm> #include <map> #include <set> #include <string> #include <vector> #include <string.h> #include <math.h> using namespace std; typedef long long ll; const int MAXN = 300050; int arr[MAXN]; int dp[MAXN][20];//gcd int dq[MAXN][20];//min int n; int gcd(int a,int b) { return b?gcd(b,a%b):a; } bool ok(int x) { int k = (int)(log((double)(x+1)) / log(2.0)); for(int i=0;i<n-x;i++) { int j = i+x; int Min = min(dq[i][k],dq[j - (1<<k) + 1][k]); int g = gcd(dp[i][k],dp[j - (1<<k) + 1][k]); if(g==Min) return true; } return false; } void out(int x) { vector<int> v; int k = (int)(log((double)(x+1)) / log(2.0)); if(x>0) { for(int i=0;i<n-x;i++) { int j = i+x; int Min = min(dq[i][k],dq[j - (1<<k) + 1][k]); int g = gcd(dp[i][k],dp[j - (1<<k) + 1][k]); if(g==Min) { v.push_back(i); } } } else { for(int i=0;i<n;i++) v.push_back(i); } cout<<v.size()<<" "<<( x>0?x:0)<<endl; for(int i=0;i<v.size();i++) cout<<v[i]+1<<" "; cout<<endl; } int main() { cin>>n; for(int i=0;i<n;i++) cin>>arr[i]; for(int i=0;i<n;i++) { dp[i][0] = arr[i]; dq[i][0] = arr[i]; } for(int i=1;i<20;i++) for(int j = 0;j<n;j++) { dp[j][i]=dp[j-1][i]; dq[j][i] = dq[j-1][i]; if(j+(1<<(i-1))<n) { dq[j][i] = min(dq[j][i-1],dq[j+(1<<(i-1))][i-1]); dp[j][i] = gcd(dp[j][i-1],dp[j+(1<<(i-1))][i-1]); } } int l = 0;int r = n-1; while(l<r) { int mid = (l+r+1)/2; if(ok(mid)) l = mid; else r = mid-1; } out(l); return 0; }