• 【BZOJ3745】Norma(CDQ分治)


    【BZOJ3745】Norma(CDQ分治)

    题面

    BZOJ
    洛谷

    题解

    这种问题直接做不好做,显然需要一定的优化。考虑(CDQ)分治。
    现在唯一需要考虑的就是跨越当前中间节点的所有区间如何计算答案了。
    (mid)开始向左枚举左端点,考虑右端点的贡献。那么我们在右侧记录两个指针(p,q),分别表示左侧的最大值和最小值第一次改变的位置。这两个指针会把整个序列分成三段。
    第一段最大值和最小值都是左侧最大最小值,直接计算区间长度和就好了。
    第二段是最大值和最小值中一个被改变了,分情况讨论一下,维护右侧的区间最大最小值就可以直接算了。第三部分是最大值和最小值都被改变了,那么把式子写出来,维护一个前缀就好了。
    时间复杂度(O(nlogn))。可能实现要仔细想清楚,可以看看代码。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define ll long long
    #define MAX 500500
    #define MOD 1000000000
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int S(int l,int r){return 1ll*(l+r)*(r-l+1)/2%MOD;}
    void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;if(x<0)x+=MOD;}
    int n,ans,a[MAX];
    int sm[MAX],sp[MAX],smx[MAX],smn[MAX],smxp[MAX],smnp[MAX],mnv[MAX],mxv[MAX];
    void CDQ(int l,int r)
    {
    	if(l==r){add(ans,1ll*a[l]*a[l]%MOD);return;}
    	int mid=(l+r)>>1;CDQ(l,mid);CDQ(mid+1,r);
    	int mn=a[mid],mx=a[mid];
    	sm[mid]=sp[mid]=smx[mid]=smn[mid]=smxp[mid]=smnp[mid]=0;
    	for(int i=mid+1;i<=r;++i)
    		if(i==mid+1)
    		{
    			mnv[i]=mxv[i]=smx[i]=smn[i]=a[i];
    			smnp[i]=smxp[i]=1ll*a[i]*i%MOD;
    			sm[i]=1ll*a[i]*a[i]%MOD;sp[i]=1ll*i*a[i]%MOD*a[i]%MOD;
    		}
    		else
    		{
    			mnv[i]=min(mnv[i-1],a[i]);
    			mxv[i]=max(mxv[i-1],a[i]);
    			add(smn[i]=smn[i-1],mnv[i]);
    			add(smx[i]=smx[i-1],mxv[i]);
    			add(smnp[i]=smnp[i-1],1ll*mnv[i]*i%MOD);
    			add(smxp[i]=smxp[i-1],1ll*mxv[i]*i%MOD);
    			add(sm[i]=sm[i-1],1ll*mnv[i]*mxv[i]%MOD);
    			add(sp[i]=sp[i-1],1ll*i*mnv[i]%MOD*mxv[i]%MOD);
    		}
    	for(int i=mid,p=mid,q=mid;i>=l;--i)
    	{
    		mn=min(mn,a[i]);mx=max(mx,a[i]);
    		while(p<r&&mnv[p+1]>=mn)++p;
    		while(q<r&&mxv[q+1]<=mx)++q;
    		add(ans,1ll*S(mid-i+2,min(p,q)-i+1)*mn%MOD*mx%MOD);
    		if(p<q)add(ans,((smnp[q]-smnp[p])-1ll*(smn[q]-smn[p])*(i-1)%MOD+MOD)*mx%MOD);
    		if(q<p)add(ans,((smxp[p]-smxp[q])-1ll*(smx[p]-smx[q])*(i-1)%MOD+MOD)*mn%MOD);
    		add(ans,(((sp[r]-sp[max(p,q)])-1ll*(sm[r]-sm[max(p,q)])*(i-1)%MOD+MOD)%MOD));
    	}
    }
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;++i)a[i]=read();
    	CDQ(1,n);printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    克隆用户过狗提权
    一个JS引发的血案
    python-标识符(Identifiers)和关键字(keywords)
    提取nmap扫描出来的xml文件
    Hydra扫描姿势
    Senparc.Weixin.MP SDK 微信公众平台开发教程(十二):OAuth2.0说明
    Senparc.Weixin.MP SDK 微信公众平台开发教程(十一):高级接口说明
    Senparc.Weixin.MP SDK 微信公众平台开发教程(十):多客服接口说明
    Senparc.Weixin.MP SDK 微信公众平台开发教程(九):自定义菜单接口说明
    Senparc.Weixin.MP SDK 微信公众平台开发教程(八):通用接口说明
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9690152.html
Copyright © 2020-2023  润新知