codeforces 689d Friends and Subsequences(rmq+ 二分)
阿新 • • 發佈:2018-12-11
題意: 給你兩個序列 你要求出有多少對 L ,R 使得A中的最大值等於B中的最小值。
思路: 先預處理出rmq 那麼列舉每一個位置,找出這個位置的最小右端點和最大右端點就可以了。那麼就用二分判斷唄。因為對於每一個位置maxx 肯定是升序的,minn 肯定是降序的。
程式碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N =2e5+5; vector<int >A; vector<int >B; int n; int mn[N][23]; int mx[N][23]; void init_rmq() { for(int i=0;i<n;i++) mx[i][0]=A[i]; for(int j=1;(1<<j)<=n;j++){ for(int i=0;i+(1<<j)-1<n;i++){ mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]); } } for(int i=0;i<n;i++) mn[i][0]=B[i]; for(int j=1;(1<<j)<=n;j++){ for(int i=0;i+(1<<j)-1<n ;i++){ mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]); } } } int maxx(int l,int r) { int k=0; while((1<<(k+1))<=r-l+1) k++; return max(mx[l][k],mx[r-(1<<k)+1][k]); } int minn(int l,int r) { int k=0; while((1<<(k+1))<=r-l+1) k++; return min(mn[l][k],mn[r-(1<<k)+1][k]); } int jud(int l,int r,int num) { int x=maxx(l,r); int y=minn(l,r); if(x==y&&x==num) return 1; return 0; } int solve(int le,int re) { int L,R; L=-1; R=-1; int l,r,mid,in=-1; l=le; r=re; while(l<=r) { mid=(l+r)>>1; int v1 =maxx(le,mid),v2=minn(le,mid); if(v1==v2){ L = mid; r = mid-1; }else if(v1<v2){ l = mid+1; }else{ r = mid-1; } } if(L==-1) return 0; l=le; r=re; while(l<=r) { mid=(l+r)>>1; int v1 = maxx(le,mid),v2=minn(le,mid); if(v1==v2){ R = mid; l = mid+1; }else if(v1<v2){ l = mid+1; }else{ r = mid-1; } } return R-L+1; } int main() { scanf("%d",&n); int x; for(int i=1;i<=n;i++){ scanf("%d",&x); A.push_back(x); } for(int i=1;i<=n;i++){ scanf("%d",&x); B.push_back(x); } init_rmq(); ll ans=0; for(int i=0;i<n;i++){ ans+=1ll*solve(i,n-1); } printf("%lld\n",ans); return 0; }