LOJ#6101. 「2017 山东二轮集训 Day1」第二题 题解

题目链接

按照最小值分治到两边,然后直接做即可。

\(\Theta(n\log n)\) , 如果 \(\Theta(n)\) 建笛卡尔树可以做到 \(\Theta(n)\) .

code :

#include <bits/stdc++.h>
#define LL long long
using namespace std;
template <typename T> void read(T &x){
	static char ch; x = 0,ch = getchar();
	while (!isdigit(ch)) ch = getchar();
	while (isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
}
inline void write(LL x){if (x > 9) write(x/10); putchar(x%10+'0'); }

const int N = 100005;
int n,k,a[N],Log[N],mn[N][20];
struct data{
	LL ans,r;
	data(){ ans = r = 0; }
	inline void add(LL v){ r += v; if (r > 0) ans += ceil(r * 1.0 / k),r -= ceil(r * 1.0 / k) * k;  }
};
inline int Mn(int l,int r){
	static int t; t = Log[r-l+1],l = mn[l][t],r = mn[r-(1<<t)+1][t];
	return a[l] < a[r] ? l : r;
}
data solve(int l,int r,int h){
	if (l > r) return data();
	if (l == r){ data tmp; tmp.add(a[l]-h); return tmp; }
	int p = Mn(l,r); data tmp = solve(l,p-1,a[p]),R = solve(p+1,r,a[p]);
	tmp.ans += R.ans,tmp.add(R.r),tmp.add((LL)(r-l+1)*(a[p]-h));
	return tmp;
}
int main(){
	int i,j,x,y;
	read(n),read(k);
	for (i = 1; i <= n; ++i) read(a[i]),mn[i][0] = i;
	for (i = 1; i <= n; ++i){ Log[i] = Log[i-1]; if ((1<<Log[i]+1) < i) ++Log[i]; }
	for (j = 1; j <= Log[n]; ++j) for (i = 1; i+(1<<j)-1 <= n; ++i)
		x = mn[i][j-1],y = mn[i+(1<<j-1)][j-1],mn[i][j] = a[x] < a[y] ? x : y;
	write(solve(1,n,0).ans),putchar('\n');
	return 0;
}
posted @ 2020-10-03 10:37  srf  阅读(214)  评论(0编辑  收藏  举报