护甲

(problem)

在皮卡多捡到了一件三级甲的老王非常兴奋,想马上测试一下三级甲的性能,于是老王走到了加油站旁边的空地上跳俄舞,不一会儿身上就被打了一排子弹,老王躲起来后脱下三级甲,发现这一排弹孔深度不一,聪明的老王想到了一个量化计算性能的方法,给定一个(k≤n),计算出所有长度为 (k) 的区间的弹孔深度的最小值的和,当然 (k) 值不同,得到的性能值也不同,所以老王会取不同的 (k) 进行计算,为了帮助老王吃鸡,这个问题就交给你来解决。

Solution

考场上想到了代价转贡献,但是没有考虑全面,倍增处理最小值时炸了

正解其实是一个二维差分,就是贡献大概是前缀,后缀加上一段常数,可以用差分来维护

因为懒得写单调队列就写了暴力,结果一发90pts?! 再判断一个特殊性质就A了

(Code)

#include<bits/stdc++.h>
using namespace std;
#define fr(i,a,b) for(int i=a;i<=b;++i)
#define rf(i,a,b) for(int i=a;i>=b;--i)
template<typename T>
inline void read(T &x){
	char c=getchar();x=0;bool f=0;
	while(!isdigit(c))f|=(c=='-'),c=getchar();
	while(isdigit(c))x=x*10+(c^48),c=getchar();
	x=f?-x:x;
}
typedef long long ll;
const int N=1e6+5;
ll ans[N];
ll ans2[N],Ans1[N],Ans2[N],ans1[N],a[N];
int n,m,k;
int main(){
//	freopen("vest.in","r",stdin);
//	freopen("vest.out","w",stdout);
	read(n),read(m);
	int f=0;
	fr(i,1,n)read(a[i]),f|=(a[i]!=i);
	if(!f){
		while(m--){
			read(k);
			printf("%lld
",1ll*(n-k+1)*(n-k+2)/2);
		}
		return 0;
	}
	fr(i,1,n){
		int l=i,r=i+1;
		while(a[l]>=a[i]&&l)--l;++l;
		while(a[r]>a[i]&&r<=n)++r;--r;
		int nw=min(i-l+1,r-i+1),nw1=max(i-l+1,r-i+1),nw2=r-l+1;
		if(nw-1>=1)ans[1]+=a[i],ans[nw]-=a[i],Ans1[nw]-=(nw-1)*a[i];
        if(nw1+1<=nw2)ans2[nw2]+=a[i],ans2[nw1]-=a[i],Ans2[nw1]-=(nw-1)*a[i];
		ans1[nw]+=nw*a[i],ans1[nw1+1]-=nw*a[i];
	} 
	fr(i,1,n){
		ans[i]+=ans[i-1];
		Ans1[i]+=ans[i]+Ans1[i-1];//left
		ans1[i]+=ans1[i-1];//middle
	}
	rf(i,n,1){//right
		ans2[i]+=ans2[i+1];
		Ans2[i]+=Ans2[i+1]+ans2[i];
	}
	while(m--){
		read(k);
		printf("%lld
",Ans1[k]+Ans2[k]+ans1[k]);
	}
}


原文地址:https://www.cnblogs.com/coder-cjh/p/13939877.html