2019牛客暑期多校訓練營(第三場)G Removing Stones(分治+二分)

鏈接:https://ac.nowcoder.com/acm/contest/883/G
來源:牛客網
 

題目描述

給出一個n和長度爲n的序列,

求有多少個區間[l,r]滿足[SUM(L,R)/2] >= MAX(L,R)

輸入

2
3
1 1 1
4
1 2 3 4

輸出

3
3

題解:

 

魔鬼出題人卡時間。。標程寫的很簡潔也跑了600+ms。題目纔給1s。要常數小才能過。

有個尺取的假做法能過,但是複雜度容易退化到O(n^2),不是正解(數據水了。跑的比正解快)

代碼:

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 300005;
typedef long long ll;
typedef pair<int,int> P;

int n;
int a[MAXN];
int dp[MAXN][19];
int mm[MAXN];
ll sum[MAXN];
inline int cmp(const int &x, const int &y){
    return (a[x] > a[y]) ? x : y;
}
inline void init(int n){
    sum[0] = 0ll;
    for(int i = 1; i <= n; i++)
        dp[i][0] = i,
        sum[i] = sum[i-1] + a[i];
    for(int j = 1; j <= mm[n]; j++)
        for(int i = 1; i + (1<<j) - 1 <= n; i++)
            dp[i][j] = cmp(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
}
inline int rmq(const int &x, const int &y){
    int k = mm[y-x+1];
    return cmp(dp[x][k], dp[y-(1<<k)+1][k]);
}
#define sumdiv2(x,y) ((sum[y] - sum[x-1])>>1)
ll ans;
inline void dfs(int L,int R){
    if(L >= R) return;
    int k = rmq(L,R);
    ll mx = a[k];
    if(k-L<R-k){
        register int l, r = k, mid;
        for(int i = L; i <= k; i++){
            if(sumdiv2(i,R) < mx) break;
            l = r-1, r = R;
            while(l+1<r){
                mid = (l+r)>>1;
                if(sumdiv2(i, mid) >= mx)
                    r = mid;
                else
                    l = mid;
            }
            ans += R-r+1;
        }
    }else{
        register int l = k, r, mid;
        for(int i = R; i >= k; i--){
            if(sumdiv2(L,i) < mx) break;
            r = l+1, l = L;
            while(l+1<r){
                mid = (l+r)>>1;
                if(sumdiv2(mid, i) >= mx)
                    l = mid;
                else
                    r = mid;
            }
            ans += l-L+1;
        }
    }
    dfs(L,k-1); dfs(k+1,R);
}
int main()
{
    for(int i = 2; i < MAXN; i++)
        mm[i] = ((i&(i-1))==0) ? mm[i-1]+1 : mm[i-1];
    int T; scanf("%d",&T); while(T--){
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        init(n);
        ans = 0; dfs(1,n);
        printf("%lld\n", ans);
    }
    return 0;
}

 

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