[51nod1810]连续区间

来源:互联网 发布:跆拳道教学软件 编辑:程序博客网 时间:2024/05/16 15:22

Description

给出一个1~n的排列,求有多少个区间将区间内所有元素排序后,任意相邻两个元素值差为1
n<=1e6

Solution

个人认为马拉松26中最可做的一道题(然而还是没有做出来
考虑分治,也就是我们要统计左端点在[l,mid],右端点在[mid+1,r]的区间个数
设max[i]表示i到mid的前缀/后缀max,min[i]表示i到mid的前缀/后缀min
设区间左端点为i,右端点为j,我们可以知道一个合法的区间必然满足

max(max[i],max[j])min(min[i],min[j])=ji

那么我们分4种情况讨论一下
max(max[i],max[j])=max[i],min(min[i],min[j])=min[i]
那么j=max[i]min[i]+i,直接算出来判断一下是否可行即可
max(max[i],max[j])=max[i],min(min[i],min[j])=min[j]
那么max[i]+i=min[j]+j,并且可行的j一定在某一段区间中
这个区间可以线性维护,开个桶记录一下每个值出现的次数即可
后两种情况同理,那么总复杂度就是O(n log n)

Code

#include <cstdio>#include <cstring>#include <algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long ll;const int N=1e6+5;int n,a[N],b[N*3],Max[N],Min[N];ll ans;int read() {    char ch;    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());    int x=ch-'0';    for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';    return x;}void solve(int l,int r) {    int mid=(l+r)/2;    Max[mid]=Min[mid]=a[mid];    fd(i,mid-1,l) {        Max[i]=max(a[i],Max[i+1]);        Min[i]=min(a[i],Min[i+1]);    }    Max[mid+1]=Min[mid+1]=a[mid+1];    fo(i,mid+2,r) {        Max[i]=max(a[i],Max[i-1]);        Min[i]=min(a[i],Min[i-1]);    }    fd(i,mid,l) {        int j=Max[i]-Min[i]+i;        if (j>mid&&j<=r&&Max[i]>Max[j]&&Min[i]<Min[j]) ans++;    }    fo(j,mid+1,r) {        int i=-(Max[j]-Min[j]-j);        if (i>=l&&i<=mid&&Max[i]<Max[j]&&Min[i]>Min[j]) ans++;    }    int le=mid+1,ri=mid;    fd(i,mid,l) {        while (ri<r&&Max[ri+1]<Max[i]) ri++,b[Min[ri]+ri+N]++;        while (le<=ri&&Min[le]>Min[i]) b[Min[le]+le+N]--,le++;        ans+=b[Max[i]+i+N];    }    while (le<=ri) b[Min[le]+le+N]--,le++;    le=mid+1;ri=mid;    fo(j,mid+1,r) {        while (le>l&&Max[le-1]<Max[j]) le--,b[Min[le]-le+N]++;        while (ri>=le&&Min[ri]>Min[j]) b[Min[ri]-ri+N]--,ri--;        ans+=b[Max[j]-j+N];    }    while (le<=ri) b[Min[ri]-ri+N]--,ri--;    if (l==r) return;    solve(l,mid);solve(mid+1,r);}int main() {    n=read();    fo(i,1,n) a[i]=read();    solve(1,n);    printf("%lld\n",ans+n);}
原创粉丝点击