链接: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;
}