首先先可以发现对于限制
到这里可以暴力
然后对于最大值的限制,考虑仿照
- 枚举左端点
,发现他能贡献到的右端点肯定是连续的,可以用预处理出的值算出,然后树状数组计算,这样会多一个 。但是发现是先修改再查询,所以可以差分。 - 枚举右端点
,发现可以贡献到他的左端点也是可以直接算出,维护左边的前缀和计算就行了。
由于最大值的分布位置不一定均匀,为了防止复杂度退化到
#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
const int lgn=25;
const int mod=1e9+7;
int a[maxn],pre[maxn],nxt[maxn],sum[maxn],sum2[maxn];
int que[maxn],head,tail,dp[maxn],now=1;
int st[maxn][lgn],lg[maxn];
inline void init(int n){
lg[0]=-1;
for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int j=1;j<=20;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
if(a[st[i][j-1]]>=a[st[i+(1<<(j-1))][j-1]]) st[i][j]=st[i][j-1];
else st[i][j]=st[i+(1<<(j-1))][j-1];
}
}
}
int query(int l,int r){
int k=lg[r-l+1];
if(a[st[l][k]]>=a[st[r-(1<<k)+1][k]]) return st[l][k];
return st[r-(1<<k)+1][k];
}
void cdq(int l,int r){
if(l>=r){
if(now<=l){
for(int i=now;i<l;i++){
sum[i]=(sum[i-1]+sum[i])%mod;
dp[i]=(dp[i]+sum[i])%mod;
sum2[i]=(sum2[i-1]+dp[i])%mod;
}
now=l;
}
if(l==r&&a[l]==1) dp[l]=(dp[l]+dp[l-1])%mod;
if(now<=r){
for(int i=now;i<=r;i++){
sum[i]=(sum[i-1]+sum[i])%mod;
// printf("%d %d %d : %d\n",i,sum[i],sum2[i],dp[i]);
dp[i]=(dp[i]+sum[i])%mod;
sum2[i]=(sum2[i-1]+dp[i])%mod;
// printf("%d %d %d : %d\n",i,sum[i],sum2[i],dp[i]);
}
now=r+1;
}
return;
}
int mid=query(l,r);
cdq(l,mid-1);
// for(int i=mid;i<=r;i++) sum[i]=sum2[i]=0;
if(mid-l<r-mid+1){
for(int i=l-1;i<mid;i++){
int tmp=min(r,i+a[mid]);
if(tmp<mid) continue;
if(max(mid,nxt[i+1])<=tmp){
// printf("kk%d : %d %d\n",i,max(mid,nxt[i+1]),tmp);
sum[max(mid,nxt[i+1])]=(sum[max(mid,nxt[i+1])]+dp[i])%mod;
sum[tmp+1]=(sum[tmp+1]-dp[i]+mod)%mod;
}
}
}else{
for(int i=mid;i<=r;i++){
int tmp=max(l,i-a[mid]+1);
if(tmp>mid) continue;
if(min(pre[i],mid)>=tmp){
dp[i]=(dp[i]+sum2[min(pre[i],mid)-1])%mod;
if(tmp>=2) dp[i]=(dp[i]-sum2[tmp-2]+mod)%mod;
}
}
}
cdq(mid+1,r);
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
st[i][0]=i;
}
init(n);
int mn=0;
head=1;
tail=0;
for(int i=1;i<=n;i++){
while(head<=tail&&a[que[tail]]>=a[i]) tail--;
que[++tail]=i;
while(head<=tail&&i-a[que[head]]+1>que[head]){
mn=max(mn,que[head]);
head++;
}
pre[i]=max(mn,i-a[que[head]]+1);
}
head=1;
tail=0;
mn=n+1;
for(int i=n;i>=1;i--){
while(head<=tail&&a[que[tail]]>=a[i]) tail--;
que[++tail]=i;
while(head<=tail&&i+a[que[head]]-1<que[head]){
mn=min(mn,que[head]);
head++;
}
nxt[i]=min(mn,i+a[que[head]]-1);
}
// for(int i=1;i<=n;i++) printf("%d : %d %d\n",i,pre[i],nxt[i]);
// exit(0);
sum2[0]=dp[0]=1;
cdq(1,n);
printf("%d\n",dp[n]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话