• 5231. 【NOIP2017模拟A组模拟8.5】序列问题


    这题分治。
    对于一个区间[l,r]
    我们可以分三种情况讨论:
    (设左端点为a,右端点为b)

    1:a,b都在[l,mid]

    2:a,b都在[mid+1,r]

    3:a,b跨过了mid,也就是a<=mid && b>mid

    1,2都可以从下一层求出,所以我们只需要求出ans即可。
    而3怎么求呢?
    我们设mi[],ma[],sma[],smi[],s[]
    i:

    l<=i<=mid

    mi[i]表示[i,mid]中的最小值
    ma[i]表示[i,mid]中的最大值
    smi[i]表示mi[i~mid]的和
    sma[i]表示ma[i~mid]的和
    s[i]表示∑ma[i]*mi[i](i<=mid)

    mid+1<=i<=r

    同理

    我们可以枚举左端点a(mid->l)
    然后找到右边([mid+1,r])中第一个大于ma[a]的位置u
    第一个小于mi[a]的位置v

    PS:(我们可以发现,在a向左移的时候,u,v的位置是单调递增的!!!)

    我们分成三块来求:(设u<v)

    1:[a,u-1]

    它的最大值一定是mi[a],最小值一定是ma[a],然后再乘(u-mid)

    2:[u,v-1]

    它的最大值就是ma[a],而最小值的话不确定,所以我们可以用smi[v]-smi[u]来求和

    3:[v,r]

    它的最大值和最小值都不确定!!!

    but,肯定不是mid左边的!!

    因为u,v已经是比那些还要有的了!!!

    所以我们就要用到s[]来求就可以了,为(s[r]-s[v])
    好啦,分治完后输出答案即可。

    上标:

    #include<cstdio>
    #include<algorithm>
    #define N 500010
    #define mo 1000000007
    #define ll long long
    using namespace std;
    ll a[N],smi[N],sma[N],mi[N],ma[N],s[N],ans=0;
    int n;
    
    inline int read()
    {
    	int x=0; char c=getchar();
    	while (c<'0' || c>'9') c=getchar();
    	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x;
    }
    
    void solve(int l,int r)
    {
    	if (l==r) {(ans+=a[l]*a[l])%=mo; return;}
    	int mid=l+r>>1;
    	solve(l,mid),solve(mid+1,r);
    	smi[mid]=sma[mid]=ma[mid]=s[mid]=0;
    	mi[mid]=1000000000;
    	for (int i=mid+1;i<=r;i++)
    	{
    		mi[i]=min(mi[i-1],a[i]),ma[i]=max(ma[i-1],a[i]);
    		smi[i]=(smi[i-1]+mi[i])%mo,sma[i]=(sma[i-1]+ma[i])%mo;
    		s[i]=(s[i-1]+mi[i]*ma[i])%mo;
    	}
    	ll mil=1000000000,mal=0,u=mid+1,v=mid+1;
    	for (int i=mid;i>=l;i--)
    	{
    		mil=min(mil,a[i]),mal=max(mal,a[i]);
    		while (mi[u]>mil && u<=r) u++;u--;
    		while (ma[v]<mal && v<=r) v++;v--;
    		if (u<v)
    		{
    			(ans+=(u-mid)*mal%mo*mil%mo)%=mo;
    			(ans+=(smi[v]-smi[u]+mo)%mo*mal%mo)%=mo;
    			(ans+=s[r]-s[v])%=mo;
    		}
    		else
    		{
    			(ans+=(v-mid)*mal%mo*mil%mo)%=mo;
    			(ans+=(sma[u]-sma[v]+mo)%mo*mil%mo)%=mo;
    			(ans+=s[r]-s[u])%=mo;
    		}
    	}
    }
    
    int main()
    {
    	freopen("seq.in","r",stdin);
    	freopen("seq.out","w",stdout);
    	n=read();
    	for (int i=1;i<=n;i++) a[i]=read();
    	solve(1,n);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    转载需注明出处。
  • 相关阅读:
    【可视化】指标块分析
    【可视化】可视化概况(一)
    webpack 打包编译优化之路
    Akka源码分析-Akka-Streams-概念入门
    Akka源码分析-Cluster-DistributedData
    Akka源码分析-Cluster-Sharding
    Akka源码分析-Cluster-Metrics
    Akka源码分析-Cluster-Distributed Publish Subscribe in Cluster
    Akka源码分析-Cluster-ClusterClient
    Akka源码分析-Cluster-Singleton
  • 原文地址:https://www.cnblogs.com/jz929/p/11817624.html
Copyright © 2020-2023  润新知