HDU6701:Make Rounddog Happy(啓發式分治)

題意:給定數組a[],求區間個數,知足區間的數各不一樣,並且知足maxval-len<=K;html

思路:一看就能夠分治作,對於當前的區間,從max位置分治。 對於這一層,須要高效的統計答案,那麼對短的一邊開始統計。c++

(這個過程很像啓發式的逆過程,因此叫作啓發式分治數組

1,對於數不一樣,這個能夠預處理前綴和後綴的最大區間長度A[],B[]。spa

2,st表獲得區間最大值位置,而後就能夠搞了。code

若是是第一次遇到,能夠參考同一類的題目:htm

2019牛客暑期多校訓練營(第三場)G: Removing Stones(啓發式分治)blog

Non-boring sequences(啓發式分治)get

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std; const int maxn=1000010; int a[maxn],st[maxn][21],lg[maxn],K,N; ll ans; int A[maxn],B[maxn],vis[maxn]; int get(int L,int R) { int k=lg[R-L+1]; return a[st[L][k]]>=a[st[R-(1<<k)+1][k]]?st[L][k]:st[R-(1<<k)+1][k]; } void solve(int L,int R) { if(L>R) return ; int pos=get(L,R); if(pos-L<R-pos){ rep(i,L,pos){ int t=a[pos]-K,lR=i+t-1; int fcy=min(R,B[i]); lR=max(lR,pos); if(lR>fcy) continue; ans+=fcy-lR+1; } } else { rep(i,pos,R){ int t=a[pos]-K,rL=i-t+1; int fcy=max(L,A[i]); rL=min(rL,pos); if(rL<fcy) continue; ans+=rL-fcy+1; } } solve(L,pos-1); solve(pos+1,R); } int main() { int T; lg[0]=-1; rep(i,1,maxn-1) lg[i]=lg[i>>1]+1; scanf("%d",&T); while(T--){ scanf("%d%d",&N,&K); ans=0; rep(i,1,N) scanf("%d",&a[i]); rep(i,1,N) st[i][0]=i; rep(i,1,20) { rep(j,1,N+1-(1<<i)) st[j][i]=a[st[j][i-1]]>=a[st[j+(1<<(i-1))][i-1]]?st[j][i-1]:st[j+(1<<(i-1))][i-1]; } rep(i,1,N) vis[i]=0; A[1]=1; vis[a[1]]=1; rep(i,2,N){ if(vis[a[i]])  A[i]=max(A[i-1],vis[a[i]]+1); else A[i]=A[i-1]; vis[a[i]]=i; } rep(i,1,N) vis[i]=0; B[N]=N; vis[a[N]]=N; for(int i=N-1;i>=1;i--){ if(vis[a[i]]) B[i]=min(B[i+1],vis[a[i]]-1); else B[i]=B[i+1]; vis[a[i]]=i; } solve(1,N); printf("%lld\n",ans); } return 0; }
相關文章
相關標籤/搜索