區間分治—19牛客多校 3 G Removing Stones

19牛客多校 3 G

題意:給你一個數組,求滿足一個區間(l,r)的最大值大於等於其區間和的1/2(l!=r)

思路:區間分治 把最大值作爲分界線。

#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <map>
#include <iterator>
#include <vector>
#include <set>
#include <bitset>
#include <stack>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define mems(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int N=3e5+10;

int a[N],lg[N],dp[N][20],n;
ll sum[N],sum1[N],ans;
void RMQ()
{
    for(int i=1;i<=n;i++)
        dp[i][0]=i;//裏面存的下標
    for(int i=1;(1<<i)<=n;i++)
    {
        int d=(1<<i);
        for(int j=1;j+d-1<=n;j++)
        {
            dp[j][i]=a[dp[j][i-1]]>=a[dp[j+(1<<(i-1))][i-1]]?
            dp[j][i-1]:dp[j+(1<<(i-1))][i-1];
        }
    }
}

void solve(int x,int y)
{
    if(x>=y)
        return;
    int k=lg[y-x+1];//分區間大小
    int mid=(a[dp[x][k]]>=a[dp[y-(1<<k)+1][k]]?
             dp[x][k]:dp[y-(1<<k)+1][k]);
    if(mid-x<y-mid)//最大值在左
    {
        for(int i=x; i<=mid; i++)
        {
          int pos=lower_bound(sum+mid,sum+y+1,sum[i-1]+2LL*a[mid])-sum;
            ans+=y-pos+1;
        }
    }
    else
    {
        for(int i=mid; i<=y; i++)
        {
  int pos=lower_bound(sum1+n-mid+1,sum1+n-x+2,sum1[n-i]+2LL*a[mid])-sum1;
            ans+=n+1-x-pos+1;

        }
    }
    solve(x,mid-1);
    solve(mid+1,y);
}


int main()
{
    lg[0]=-1;
    for(int i=1; i<N; i++)
    {
        lg[i]=lg[i>>1]+1;
    }
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ans=0;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        for(int i=1; i<=n; i++)
            sum1[i]=sum1[i-1]+a[n-i+1];
        RMQ();
        solve(1,n);
        printf("%lld\n",ans);
    }
    return 0;
}

19hdu多校-10 6701 Make Rounddog Happy

題意:

max(al,al+1,…,ar)−(r−l+1)≤k.

思路:

還是區間分治。

#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <map>
#include <iterator>
#include <vector>
#include <set>
#include <bitset>
#include <stack>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define mems(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1e6+10;
int a[N],lg[N],dp[N][20],n,m;
int A[N],B[N],vis[N];ll ans;
void RMQ()
{
    for(int i=1; i<=n; i++)
        dp[i][0]=i;///裏面存的下標
    for(int i=1; (1<<i)<=n; i++)
    {
        int d=(1<<i);
        for(int j=1; j+d-1<=n; j++)
        {
            dp[j][i]=a[dp[j][i-1]]>=a[dp[j+(1<<(i-1))][i-1]]?
                     dp[j][i-1]:dp[j+(1<<(i-1))][i-1];
        }
    }
}
int get(int L,int R)
{
    int k=lg[R-L+1];
    return a[dp[L][k]]>=a[dp[R-(1<<k)+1][k]]?dp[L][k]:dp[R-(1<<k)+1][k];
}
void solve(int l,int r)
{
    if(r<l)
        return;
    int k=lg[r-l+1];///分區間大小
    int mid=(a[dp[l][k]]>=a[dp[r-(1<<k)+1][k]]?
             dp[l][k]:dp[r-(1<<k)+1][k]);
    int len=a[mid]-m;
    if(mid-l<r-mid)
    {
        for(int i=mid; i>=l; i--)
        {
            int L=max(mid,i+len-1);
            int R=min(B[i],r);
            if(R>=L)
                ans+=R-L+1;
        }
    }
    else
    {
        for(int i=mid; i<=r; i++)
        {
            int L=max(l,A[i]);
            int R=min(i-len+1,mid);
            if(R>=L)
                ans+=R-L+1;
        }
    }
    solve(l,mid-1);
    solve(mid+1,r);
}

int main()
{
    lg[0]=-1;
    for(int i=1; i<N; i++)
    {
        lg[i]=lg[i>>1]+1;
    }
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ans=0;
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
        }
        RMQ();
        for(int i=1;i<=n;i++) vis[i]=0;
        for(int i=1;i<=n;i++){
            A[i]=vis[a[i]]+1;
            vis[a[i]]=i;
        }
        for(int i=2;i<=n;i++) A[i]=max(A[i-1],A[i]);///防止出現1 2 3 2 1這種情況
        for(int i=n;i>=1;i--) vis[i]=n+1;
        for(int i=n;i>=1;i--){
            B[i]=vis[a[i]]-1;
            vis[a[i]]=i;
        }
        for(int i=n-1;i>=1;i--) B[i]=min(B[i+1],B[i]);
        solve(1,n);
        printf("%lld\n",ans);
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章