zoukankan      html  css  js  c++  java
  • BZOJ3745:[COCI2015]Norma

    浅谈离线分治算法:https://www.cnblogs.com/AKMer/p/10415556.html

    题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=3745

    我们对于所有区间,要么在分治的(mid)左边,要么在分治的(mid)右边,我们可以递归去处理。

    所以我们只需要知道怎么快速统计经过(mid)的区间的答案即可。

    我们从大到小枚举区间的左端点(x),然后计算(sumlimits_{y=mid+1}^{r}ans[x][y])(ans[x][y])表示区间([x,y])对答案的贡献。

    假设区间([x,mid])的最小值是(a),最大值(b)

    区间([mid+1,q])的最小值比(a)大,最大值比(b)小。

    区间([q+1,p])的最小值比(a)大,最大值比(b)大,或者最小值比(a)小,最大值比(b)小。

    区间([p+1,r])的最小值小于(a),最大值大于(b)

    (mn[i])表示([mid+1,i])的最小值,(mx[i])表示([mid+1,i])的最大值。

    当右端点落在这三段时,对答案的贡献分别计算。

    第一段([mid+1,q])对答案的贡献:

    (sumlimits_{i=mid+1}^{q}ab(i-x+1)=frac{ab(mid+2-x)(q-x+1)(q-mid)}{2})

    第二段([q+1,p])对答案的贡献:

    假如这一段最小值比(a)大,最大值比(b)大:

    (sumlimits_{i=q+1}^{p}a*mx[i]*(i-x+1))

    化开得:(a*(sumlimits_{i=q+1}^{p}mx[i]*i-(x-1)sumlimits_{i=q+1}^{p}mx[i]))

    (sum[1][y])表示(sumlimits_{i=mid+1}^{y}mx[i]*i)(sum[2][y])表示(sumlimits_{i=mid+1}^{y}mx[i])

    那么对答案的贡献就可以表示为(a*(sum[1][p]-sum[1][q]-(x-1)*(sum[2][p]-sum[2][q]))

    假如这一段最小值比(a)小,最大值比(b)小,同理可得:

    (sum[3][y])表示(sumlimits_{i=mid+1}^{y}mn[i]*i)(sum[4][y])表示(sumlimits_{i=mid+1}^{y}mn[i])

    对答案的贡献可以表示为(b*(sum[3][p]-sum[3][q]-(x-1)*(sum[4][p]-sum[4][q])))

    第三段对答案的贡献:

    (sumlimits_{i=p+1}^{r}mn[i]*mx[i]*(i-x+1))

    可以化为(sumlimits_{i=p+1}^{r}mx[i]*mn[i]*i-(x-1)*sumlimits_{i=p+1}^{r}mn[i]*mx[i])

    (sum[5][y])表示(sumlimits_{i=mid+1}^{y}mx[i]*mn[i]*i)(sum[6][y])表示(sumlimits_{i=mid+1}^{y}mn[i]*mx[i])

    对答案的贡献可以表示为(sum[5][r]-sum[5][p]-(x-1)*(sum[6][r]-sum[6][p]))

    所以只需要扫一遍就可以统计当前分治层的答案了。

    时间复杂度:(O(nlogn))

    空间复杂度:(O(n))

    代码如下:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define sqr(x) (1ll*(x)*(x)%pps)
    
    const int maxn=5e5+5,pps=1e9,inf=2e9;
    
    int n,ans;
    int sum[7][maxn];
    int num[maxn],mn[maxn],mx[maxn];
    
    int read() {
    	int x=0,f=1;char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    	return x*f;
    }
    
    void clear(int pos) {
    	mn[pos]=inf,mx[pos]=-inf;
    	for(int i=1;i<7;i++)
    		sum[i][pos]=0;
    }
    
    int calc(int a,int b) {
    	int c=a+b,d=b-a+1;
    	if(c%2==0)c/=2;
    	else d/=2;
    	return 1ll*c*d%pps;
    }
    
    void solve(int l,int r) {
    	if(l==r) {
    		ans=(ans+sqr(num[l]))%pps;
    		return;
    	}
    	int mid=(l+r)>>1;
    	solve(l,mid),solve(mid+1,r);
    	clear(mid);
    	for(int i=mid+1;i<=r;i++) {
    		mn[i]=min(mn[i-1],num[i]);
    		mx[i]=max(mx[i-1],num[i]);
    		sum[1][i]=(sum[1][i-1]+1ll*mx[i]*i%pps)%pps;
    		sum[2][i]=(sum[2][i-1]+mx[i])%pps;
    		sum[3][i]=(sum[3][i-1]+1ll*mn[i]*i%pps)%pps;
    		sum[4][i]=(sum[4][i-1]+mn[i])%pps;
    		sum[5][i]=(sum[5][i-1]+1ll*mn[i]*mx[i]%pps*i%pps)%pps;
    		sum[6][i]=(sum[6][i-1]+1ll*mn[i]*mx[i]%pps)%pps;
    	}
    	int a=inf,b=-inf,limit1=mid,limit2=mid;
    	for(int x=mid;x>=l;x--) {
    		a=min(a,num[x]),b=max(b,num[x]);
    		while(mn[limit1+1]>=a&&limit1<r)limit1++;
    		while(mx[limit2+1]<=b&&limit2<r)limit2++;
    		int q=min(limit1,limit2),p=max(limit1,limit2);
    		ans=(ans+(1ll*a*b%pps*calc(mid+2-x,q-x+1)%pps))%pps;
    		if(q==limit2)ans=(ans+1ll*a*(sum[1][p]-sum[1][q]-1ll*(x-1)*(sum[2][p]-sum[2][q])%pps)%pps)%pps;
    		else ans=(ans+1ll*b*(sum[3][p]-sum[3][q]-1ll*(x-1)*(sum[4][p]-sum[4][q])%pps)%pps)%pps;
    		ans=(ans+sum[5][r]-sum[5][p]-1ll*(x-1)*(sum[6][r]-sum[6][p])%pps)%pps;
    	}
    }
    
    int main() {
    	n=read();
    	for(int i=1;i<=n;i++)
    		num[i]=read();
    	solve(1,n);ans=(ans+pps)%pps;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    P1144 最短路计数 题解 最短路应用题
    C++高精度加减乘除模板
    HDU3746 Teacher YYF 题解 KMP算法
    POJ3080 Blue Jeans 题解 KMP算法
    POJ2185 Milking Grid 题解 KMP算法
    POJ2752 Seek the Name, Seek the Fame 题解 KMP算法
    POJ2406 Power Strings 题解 KMP算法
    HDU2087 剪花布条 题解 KMP算法
    eclipse创建maven项目(详细)
    maven的作用及优势
  • 原文地址:https://www.cnblogs.com/AKMer/p/10426924.html
Copyright © 2011-2022 走看看