1. 程式人生 > 實用技巧 >CF359D Pair of Numbers(ST+二分)

CF359D Pair of Numbers(ST+二分)

首先觀察到答案具有二分性,因此考慮二分答案。

對於check函式,樸素的想法就是列舉每個長度為mid的區間查詢

我們發現區間gcd就等於區間最小值,因此考慮維護區間最小值和區間gcd

可以使用線段樹維護,但是我們發現區間gcd也能使用st表維護

因此直接用st表維護這兩個

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
typedef pair<int,pll> plll;
const int N=5e5+10;
const
int inf=0x3f3f3f3f; const int mod=1e9+7; int a[N],f[N][30]; int g[N][30]; int lg[N],n; int gcd(int a,int b){ return b?gcd(b,a%b):a; } void init(){ int i,j; lg[1]=0; lg[2]=1; for(i=3;i<N;i++) lg[i]=lg[i>>1]+1; for(i=1;i<=n;i++){ f[i][0]=g[i][0]=a[i]; }
for(j=1;j<=25;j++){ for(i=1;i+(1<<j)-1<=n;i++){ f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]); g[i][j]=gcd(g[i][j-1],g[i+(1<<j-1)][j-1]); } } } int MIN(int l,int r){ return min(f[l][lg[r-l+1]],f[r-(1<<lg[r-l+1])+1][lg[r-l+1]]); }
int GCD(int l,int r){ return gcd(g[l][lg[r-l+1]],g[r-(1<<lg[r-l+1])+1][lg[r-l+1]]); } bool check(int mid){ int i; for(i=1;i+mid-1<=n;i++){ int j=i+mid-1; int x=MIN(i,j); int y=GCD(i,j); if(x==y) return true; } return false; } vector<int> num; int main(){ ios::sync_with_stdio(false); cin>>n; int i; for(i=1;i<=n;i++){ cin>>a[i]; } int j; init(); int l=1,r=n; while(l<r){ int mid=l+r+1>>1; if(check(mid)) l=mid; else r=mid-1; } for(i=1;i+l-1<=n;i++){ int j=i+l-1; int x=MIN(i,j); int y=GCD(i,j); if(x==y) num.push_back(i); } cout<<(int)num.size()<<" "<<l-1<<endl; for(auto x:num){ cout<<x<<" "; } cout<<endl; return 0; }
View Code