[BZOJ3745][COCI2015]Norma(分治)

3745: [Coci2015]Norma

Time Limit: 20 Sec  Memory Limit: 64 MB
Submit: 563  Solved: 249
[Submit][Status][Discuss]

Description

Input

第1行,一个整数N;

第2~n+1行,每行一个整数表示序列a。

Output

输出答案对10^9取模后的结果。

Sample Input

4
2
4
1
4

Sample Output

109

【数据范围】
N <= 500000
1 <= a_i <= 10^8

HINT

Source

鸣谢 Dzy

[Submit][Status][Discuss]

分治(可以用线段树做,一般分治都是用来代替数据结构的)一般分三种:

  1.CDQ分治,在高维偏序中用来处理一维。 (处理在线修改多询问问题)

  2.线段树分治,当修改可分裂可撤销时较有效。(处理离线修改全询问问题)

  3.二分或三分,处理单调或单峰函数极值问题时有效。(处理在线修改多询问问题)

  4.“mid型”,类似树分治,统计跨过mid的区间总数,然后递归道两边继续统计。(处理无修改全询问问题)

具体到这一题,显然是最后一种方法。

https://blog.csdn.net/lych_cys/article/details/51203960

分类讨论一波,处理各种前缀和即可。

不想考虑取模和炸int的问题的话就在确定正确性之前全用long long吧。。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 typedef long long ll;
 5 using namespace std;
 6
 7 const int N=500100,mod=1000000000;
 8 int n,ans,a[N],f[N],g[N],Min[N],Max[N],Smn[N],Smx[N],Mmn[N],Mmx[N];
 9
10 int sum(int l,int r){ return (1ll*(l+r)*(r-l+1)>>1)%mod; }
11
12 void solve(int l,int r){
13     if (l==r) { ans=(ans+1ll*a[l]*a[l])%mod; return; }
14     int mid=(l+r)>>1; int mn=mod,mx=-mod;
15     solve(l,mid); solve(mid+1,r);
16     for (int i=mid; i>=l; i--) Min[i]=mn=min(mn,a[i]),Max[i]=mx=max(mx,a[i]);
17
18     mn=mod,mx=-mod;
19     g[mid]=f[mid]=Smn[mid]=Smx[mid]=Mmn[mid]=Mmx[mid]=0;
20     rep(i,mid+1,r){
21         Min[i]=mn=min(mn,a[i]); Max[i]=mx=max(mx,a[i]);//min/max
22         Smn[i]=(Smn[i-1]+Min[i])%mod; Smx[i]=(Smx[i-1]+Max[i])%mod;//sufsum of min/max
23         Mmn[i]=(Mmn[i-1]+1ll*Min[i]*i)%mod; Mmx[i]=(Mmx[i-1]+1ll*Max[i]*i)%mod;//sufsum of i*min/max
24         g[i]=(g[i-1]+1ll*mn*mx)%mod; f[i]=(f[i-1]+1ll*i*mn%mod*mx)%mod;//sufsum of min*max && sufsum of i*min*max
25     }
26
27     int j=mid,k=mid;
28     for (int i=mid; i>=l; i--){
29         while (j<r && Min[i]<a[j+1]) j++;
30         while (k<r && Max[i]>a[k+1]) k++;
31         ans=(ans+1ll*Min[i]*Max[i]%mod*sum(mid-i+2,min(j,k)-i+1))%mod;//[mid+1,min(j,k)]
32         ans=((ans+f[r]-f[max(j,k)]-1ll*(g[r]-g[max(j,k)])*(i-1)%mod)%mod+mod)%mod;//[max(j+k)+1,r]
33         if (j<k) ans=(ans+1ll*Max[i]*(Mmn[k]-Mmn[j]-1ll*(i-1)*(Smn[k]-Smn[j])%mod)%mod+mod)%mod;//[j+1,k]
34             else  ans=(ans+1ll*Min[i]*(Mmx[j]-Mmx[k]-1ll*(i-1)*(Smx[j]-Smx[k])%mod)%mod+mod)%mod;//[k+1,j]
35     }
36 }
37
38 int main(){
39     freopen("bzoj3745.in","r",stdin);
40     freopen("bzoj3745.out","w",stdout);
41     scanf("%d",&n);
42     rep(i,1,n) scanf("%d",&a[i]);
43     solve(1,n); printf("%d\n",ans);
44     return 0;
45 }

原文地址:https://www.cnblogs.com/HocRiser/p/8946671.html

时间: 2024-11-06 21:14:41

[BZOJ3745][COCI2015]Norma(分治)的相关文章

bzoj3745: [Coci2015]Norma

Description Input 第1行,一个整数N: 第2~n+1行,每行一个整数表示序列a. Output 输出答案对10^9取模后的结果. 预处理每个位置的数作为最小/大值向左延伸的最大距离,线段树维护序列的前缀的后缀min和后缀max以及这个前缀的后缀对答案的贡献,在前缀末尾加入一个数可以快速维护. #include<cstdio> typedef long long i64; const int N=500007,P=1000000000; char buf[N*20],*ptr=

【BZOJ3745】[Coci2015]Norma cdq分治

[BZOJ3745][Coci2015]Norma Description Input 第1行,一个整数N: 第2~n+1行,每行一个整数表示序列a. Output 输出答案对10^9取模后的结果. Sample Input 4 2 4 1 4 Sample Output 109 [数据范围] N <= 500000 1 <= a_i <= 10^8 题解:最近做这种题好像有点多啊~(虽然我基本上都没A). 比较直接的想法就是找出区间的最大值mid,然后分治处理[l,mid-1]和[mi

bzoj 3745 [Coci2015]Norma——序列分治

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3745 如果分治,就能在本层仅算过 mid 的区间了. 可以从中间到左边地遍历左边,给右边两个指针,表示第一个更新左边造成的最小值/最大值的位置. 两个位置共同的左边可以公式算长度,用左边的最值算:两个位置共同的右边可以预处理,处理出 算上长度(相对mid的)的最值乘积求和 与 不算长度的最值乘积求和(都是前缀),把前者加到答案里,后者乘上左边到mid的长度加到答案里即可:两个位置夹着的位置

bzoj 3745: [Coci2015]Norma【分治】

参考:https://blog.csdn.net/lych_cys/article/details/51203960 真的不擅长这种-- 分治,对于一个(l,r),先递归求出(l,mid),(mid+1,r),然后这个区间对答案贡献的就是经过mid的区间 我们先预处理出mid为l的右端点的mx*mn*len的前缀和与mx*mn的前缀和,然后枚举左端点,右端点维护两个下标j,k,分别表示mn和mx在左端点时的合法右端点 然后分三种情况处理,假设j<k 1.右端点在(mid+1,j)时,直接计算 2

bzoj 3745: [Coci2015]Norma

Description 给定序列\(a_i\) 求 \[\sum_{i=1}^n \sum_{j=i}^n (j-i+1)\max\{a_i,a_{i+1}\cdots a_j\}\min\{a_i,a_{i+1}\cdots a_j\}\] Input 第1行,一个整数N: 第2~n+1行,每行一个整数表示序列a. Output 输出答案对10^9取模后的结果. Sample Input 4 2 4 1 4 Sample Output 109 [数据范围] \(N \le 500000\) \

一类分治问题

有一类关于区间最大值和最小值之类的问题,利用单调性,可以采用分治算法解决. SPOJ22343 Norma 题意,给定一个数列,定义区间的代价为区间最大值.区间最小值.区间长度的成绩,求所有区间的代价和. 既然是分治,我们肯定要处理一个数列跨过中点的答案. 假设当前数列的中点为mid,我们从mid往前扫,扫到了i. 然后根据单调性,我们越往左扫,最大值单调不降,最小值单调不增. 那么我们可以在右边维护一个指针,表示满足最大值的区间的最靠右的端点. 假设有这么一种情况,那么我们可以把区间拆成mid

LightOJ1257 Farthest Nodes in a Tree (II)(树的点分治)

题目给一棵树,边带有权值,求每一点到其他点路径上的最大权和. 树上任意两点的路径都可以看成是经过某棵子树根的路径,于是果断树分治. 对于每次分治的子树,计算其所有结点到根的距离:对于每个结点,找到另一个离根最远的且与该结点路径过根的结点,二者的距离和就是这个点在过这棵子树的根能到的最远距离. 现在问题就是怎么比较快地找到这另一个最远距离的点..两点路径过根,说明两点间不存在一点是另一点的祖先..我一开始还想用DFS序+线段树来着..想了想,想出了线性的算法: 记录每个结点属于根的哪个儿子,把当前

点分治练习: boatherds

[题面] 求一颗树上距离为K的点对是否存在 输入数据 n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径 接下来m行每行询问一个K 输出数据 对于每个K每行输出一个答案,存在输出“AYE”,否则输出”NAY”(不包含引号) 数据范围 对于30%的数据n<=100 对于60%的数据n<=1000,m<=50 对于100%的数据n<=10000,m<=100,c<=1000,K<=10000000 [思路] 树分治. 离线存储m个询问.分治判断该m个询问

HDU 5269 &amp;&amp; BestCoder #44 1002 ZYB loves Xor I (分治)

题目地址:HDU 5269 比赛的时候想到了分治的思路,但是脑残了.,.写麻烦了...调了好久也没调出来..(分治写的太少..)赛后优化了一下..就过了.. 我的思路是先排序,排序是按照的将每个数字的二进制表示倒过来的字典序从大到小排,比如样例2中的2,6,5,4,0,二进制分别是010,110,101,100,000,排序之后是 101 110 010 100 000 这样的话就把后缀相同的都给放在一块了.其实也相当于字典树,不过比赛的时候没想到字典树,只想到了分治.. 然后从末位开始找,对所