zoukankan      html  css  js  c++  java
  • CF601B Solution

    题目链接

    题解

    可以发现,只有两相邻元素之间的差会对答案做出贡献。简单证明:设(i<k<j,a_i<a_j),若(a_k>a_j>a_i)

    易得(a_k-a_i>a_j-a_i,k-i+1<j-i+1),所以(frac{a_k-a_i+a_k-a_j}{k-i+1}>frac{a_j-a_i}{j-i+1})(a_k<a_i<a_j)同理;若(a_i<a_k<a_j),因为(a_k-a_i+a_j-a_k=a_j-a_i,k-i+1<j-i+1),所以(frac{a_k-a_i+a_j-a_k}{k-i+1}>frac{a_j-a_i}{j-i+1})

    (b_i=|a_i-a_{i+1}|),对于每组询问,我们只需求出(b)数组([l,r])内子区间最大值之和。设(bf_i)(b_i)左侧最后一个(>b_i)的元素,(af_i)(b_i)右侧第一个(>b_i)的元素,(b_i)作为最大值的区间即为((bf_i,af_i)),可对答案产生贡献的区间数为((af_i-i)cdot (i-bf_i))。维护单调递减的单调栈,正反两边求出(bf,af)数组,即可在(O(1))时间内计算(b_i)对答案的贡献值。总时间复杂度(O(nq))

    AC代码

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=1e5+10;
    int a[N],b[N],bf[N],af[N],st[N],top;
    signed main()
    {
    	int n,q,l,r,ans;
    	scanf("%lld%lld",&n,&q);
    	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    	for(int i=1;i<n;i++) b[i]=abs(a[i]-a[i+1]);
    	while(q--)
    	{
    		scanf("%lld%lld",&l,&r);
    		top=ans=0;
    		for(int i=l;i<r;i++)
    		{
    			while(top>0 && b[st[top]]<=b[i]) top--;
    			bf[i]=st[top]; st[++top]=i;
    		}
    		top=0;
    		for(int i=r-1;i>=l;i--)
    		{
    			while(top>0 && b[st[top]]<b[i]) top--;
    			af[i]=st[top]; st[++top]=i;
    		}
    		for(int i=l;i<r;i++) 
    		{
    			if(!bf[i]) bf[i]=l-1;
    			if(!af[i]) af[i]=r;
    		}
    		for(int i=l;i<r;i++) ans+=b[i]*(i-bf[i])*(af[i]-i);
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Codeforces 938G(cdq分治+可撤销并查集+线性基)
    codeforces 938F(dp+高维前缀和)
    寒武纪camp Day6
    寒武纪camp Day5
    寒武纪camp Day4
    bzoj4161 (k^2logn求线性递推式)
    loj10003加工生产调度
    loj10002喷水装置
    loj10001种树
    bzoj1023
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14641472.html
Copyright © 2011-2022 走看看