CodeChef-SAFPAR

不会高妙做法。 😦

首先拆条件:

  • \(\min \le j-i+1\)

  • \(j-i+1\le \max\)

第一个条件发现越长,越容易满足,是有单调性的。因此可以直接维护能达到的区间(使用 ST 表)。

第二个条件,考虑 cdq 分治优化 dp。假设已经求出了 \(l\sim mid\) 要更新 \(mid+1,r\),注意是 \(i=l+1\sim mid+1\)\(j\)

有两种情况:

  • \(\max\) 在左边。

  • \(\max\) 在右边。

第一种是一个点更新一个区间,第二种是一个点被一个区间贡献。为了维护,还要记录一个值控制的区间,也就是是那个区间的最大值。一个差分一个前缀和维护。

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

const int N = 5e5+5;
const ll mod = 1e9+7;

int n,a[N],st[N][20],lg[N],lf[N],rt[N],stk[N],top,mx[N],mn[N];
ll dp[N],cf[N],sm[N];

int qy(int l,int r){
    int t=lg[r-l+1];
    return min(st[l][t],st[r-(1<<t)+1][t]);
}

void sol(int l,int r){
    if (l==r){
        return;
    }
    int mid=l+r>>1;
    sol(l,mid);
    for (int i=l,j=mid+1; i<=mid; i++){
        while (j<=r && qy(i+1,j)>j-i) j++;
        mx[i]=j;
    }
    for (int j=r,i=mid; j>mid; j--){
        while (i>=l && qy(i+1,j)>j-i) i--;
        mn[j]=i;
    }
    for (int j=mid; j<=r; j++) cf[j]=0;
    int Mx=0,ps=0;
    for (int i=mid; i>=l; i--){
        if (a[i+1]>Mx) Mx=a[i+1],ps=i;
        int rb=rt[ps+1]-1;
        // j-i<=Mx
        rb=min(rb,Mx+i); rb=min(rb,r);
        if (mx[i]<=rb) cf[mx[i]]+=dp[i],cf[rb+1]-=dp[i];
    }
    for (int j=mid+1; j<=r; j++){
        cf[j]+=cf[j-1],dp[j]+=cf[j];
        cf[j]%=mod,dp[j]%=mod;
    }
    sm[l-1]=0,sm[l]=dp[l];
    for (int i=l+1; i<=mid; i++) sm[i]=(sm[i-1]+dp[i]),sm[i]%=mod;
    Mx=ps=0;
    for (int j=mid+1; j<=r; j++){
        if (a[j]>Mx) Mx=a[j],ps=j;
        if (ps==mid+1) continue;
        int lb=lf[ps];
        lb=max(lb,j-Mx); lb=max(lb,l);
        if (lb<=mn[j]) dp[j]=(dp[j]+sm[mn[j]]-sm[lb-1]+mod)%mod;
    }
    sol(mid+1,r);
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin>>n;
    for (int i=1; i<=n; i++) cin>>a[i],st[i][0]=a[i];
    for (int i=2; i<N; i++) lg[i]=lg[i/2]+1;
    for (int i=1; i<20; i++){
        for (int j=1; j+(1<<i)-1<=n; j++){
            st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);
        }
    }
    stk[++top]=0;
    for (int i=1; i<=n; i++){
        while (top>1 && a[stk[top]]<a[i]) top--;
        lf[i]=stk[top],stk[++top]=i;
    }
    stk[top=1]=n+1;
    for (int i=n; i; i--){
        while (top>1 && a[stk[top]]<=a[i]) top--;
        rt[i]=stk[top],stk[++top]=i;
    }
    dp[0]=1;
    sol(0,n);
    cout<<(dp[n]%mod+mod)%mod<<"\n";
    return 0;
}
posted @ 2025-08-06 15:51  SFlyer  阅读(26)  评论(0)    收藏  举报