zoukankan      html  css  js  c++  java
  • HDU6701:Make Rounddog Happy(启发式分治)

    题意:给定数组a[],求区间个数,满足区间的数各不同,而且满足maxval-len<=K;

    思路:一看就可以分治做,对于当前的区间,从max位置分治。 对于这一层,需要高效的统计答案,那么对短的一边开始统计。

    (这个过程很像启发式的逆过程,所以叫做启发式分治

    1,对于数不同,这个可以预处理前缀和后缀的最大区间长度A[],B[]。

    2,st表得到区间最大值位置,然后就可以搞了。

    如果是第一次遇到,可以参考同一类的题目:

    2019牛客暑期多校训练营(第三场)G: Removing Stones(启发式分治)

    Non-boring sequences(启发式分治)

    #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
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    常见的四种文本自动分词详解及IK Analyze的代码实现
    用java语言通过POI实现word文档的按标题提取
    spark的运行模式
    团队冲刺日志2
    简单之美-软件开发实践者的思考 03
    简单之美-软件开发实践者的思考 02
    简单之美-软件开发实践者的思考 01
    学习进度 15
    构建之法 06
    构建之法 05
  • 原文地址:https://www.cnblogs.com/hua-dong/p/11389968.html
Copyright © 2011-2022 走看看