E. Special Segments of Permutation(双指针&分治)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了E. Special Segments of Permutation(双指针&分治)相关的知识,希望对你有一定的参考价值。
E. Special Segments of Permutation(双指针&分治)
思路1:预处理向左、向右第一个大于 a i a_i ai的数 l [ i ] , r [ i ] l[i],r[i] l[i],r[i]。跑两边单调栈即可。
然后枚举每个点作为最大值向两边扩展,因为是对称的,所以每次只需扫较短的那一半区间,每次减少一半,每个数最多被遍历 l o g n logn logn 次。
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
// Problem: CF1156E Special Segments of Permutation
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1156E
// Memory Limit: 500 MB
// Time Limit: 2000 ms
// Date: 2021-08-26 10:37:41
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=2e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=b;i>=a;--i)
#define ios ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
}
int n,a[N],p[N],l[N],r[N],s[N],tp;
int main(){
scanf("%d",&n);
rep(i,1,n) scanf("%d",&a[i]),p[a[i]]=i;
rep(i,1,n){
while(tp&&a[s[tp]]<a[i]) tp--;
l[i]=s[tp],s[++tp]=i;
}
s[tp=0]=n+1;
per(i,1,n){
while(tp&&a[s[tp]]<a[i]) tp--;
r[i]=s[tp],s[++tp]=i;
}
int ans=0;
rep(i,1,n){
if(i-l[i]<r[i]-i){
rep(j,l[i]+1,i-1)
if(p[a[i]-a[j]]>i&&p[a[i]-a[j]]<r[i]) ans++;
}
else {
per(j,i+1,r[i]-1)
if(p[a[i]-a[j]]>l[i]&&p[a[i]-a[j]]<i) ans++;
}
}
printf("%d\\n",ans);
return 0;
}
思路2分治,对于不跨越中点的区间直接递归,否则先假设最大值在右边,枚举右端 R R R,同理再假设最大值在左边,枚举左端点 L L L。
时间复杂度: O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "cmath"
#include "vector"
#include "map"
#include "set"
#include "queue"
using namespace std;
#define MAXN 200006
//#define int long long
#define rep(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++i)
#define per(i, a, b) for (int i = (a), i##end = (b); i >= i##end; --i)
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define vi vector<int>
#define all(x) (x).begin() , (x).end()
#define mem( a ) memset( a , 0 , sizeof a )
#define min( a , b ) ( (a) < (b) ? (a) : (b) )
#define max( a , b ) ( (a) > (b) ? (a) : (b) )
#define P 998244353
typedef long long ll;
int n , m;
int A[MAXN];
long long ans = 0;
set<int> S;
void solve( int l , int r ) {
if( l == r ) return;
int mid = l + r >> 1;
int L = mid + 1 , R = mid + 1 , mxr = 0 , mxl;
S.clear();
for( ; R <= r ; ++ R ) {
mxr = max( mxr , A[R] );
while( L > l && A[L - 1] < mxr ) -- L , S.insert( A[L] );
if( S.find( mxr - A[R] ) != S.end() ) ++ ans;
}
L = mid , R = mid , mxl = 0;
S.clear();
for( ; L >= l ; -- L ) {
mxl = max( mxl , A[L] );
while( R < r && A[R + 1] < mxl ) ++ R , S.insert( A[R] );
if( S.find( mxl - A[L] ) != S.end() ) ++ ans;
}
solve( l , mid ) , solve( mid + 1 , r );
}
void solve() {
cin >> n;
rep( i , 1 , n ) scanf("%d",A + i);
solve( 1 , n );
cout << ans << endl;
}
signed main() {
// freopen("input","r",stdin);
// freopen("fuckout","w",stdout);
// int T;cin >> T;while( T-- ) solve();
solve();
}
以上是关于E. Special Segments of Permutation(双指针&分治)的主要内容,如果未能解决你的问题,请参考以下文章
CF1156E Special Segments of Permutation