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

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

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

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

我们从大到小枚举区间的左端点\(x\),然后计算\(\sum\limits_{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]\)对答案的贡献:

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

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

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

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

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

令\(sum[1][y]\)表示\(\sum\limits_{i=mid+1}^{y}mx[i]*i\),\(sum[2][y]\)表示\(\sum\limits_{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]\)表示\(\sum\limits_{i=mid+1}^{y}mn[i]*i\),\(sum[4][y]\)表示\(\sum\limits_{i=mid+1}^{y}mn[i]\)

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

第三段对答案的贡献:

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

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

令\(sum[5][y]\)表示\(\sum\limits_{i=mid+1}^{y}mx[i]*mn[i]*i\),\(sum[6][y]\)表示\(\sum\limits_{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\n",ans);
return 0;
}

BZOJ3745:[COCI2015]Norma的更多相关文章

  1. 【BZOJ3745】[Coci2015]Norma cdq分治

    [BZOJ3745][Coci2015]Norma Description Input 第1行,一个整数N: 第2~n+1行,每行一个整数表示序列a. Output 输出答案对10^9取模后的结果. ...

  2. [BZOJ3745][COCI2015]Norma[分治]

    题意 题目链接 分析 考虑分治,记当前分治区间为 \(l,r\) . 枚举左端点,然后发现右端点无非三种情况: 极大极小值都在左边; 有一个在左边; 极大极小值都在右边; 考虑递推 \(l\) 的同时 ...

  3. bzoj3745: [Coci2015]Norma

    Description Input 第1行,一个整数N: 第2~n+1行,每行一个整数表示序列a. Output 输出答案对10^9取模后的结果. 预处理每个位置的数作为最小/大值向左延伸的最大距离, ...

  4. bzoj3745: [Coci2015]Norma 分治,单调队列

    链接 bzoj 思路 首先\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=i}^{j}max(a_k)\)可以用单调队列求解.参见 ...

  5. BZOJ 3745: [Coci2015]Norma(分治)

    题意 给定一个正整数序列 \(a_1, a_2, \cdots, a_n\) ,求 \[ \sum_{i=1}^{n} \sum_{j=i}^{n} (j - i + 1) \min(a_i,a_{i ...

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

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3745 如果分治,就能在本层仅算过 mid 的区间了. 可以从中间到左边地遍历左边,给右边两个 ...

  7. bzoj 3745: [Coci2015]Norma【分治】

    参考:https://blog.csdn.net/lych_cys/article/details/51203960 真的不擅长这种-- 分治,对于一个(l,r),先递归求出(l,mid),(mid+ ...

  8. BZOJ3745 / SP22343 NORMA2 - Norma 分治,CDQ分治

    要命的题目. 写法:分类讨论进行计算. 枚举过每一个\(mid\)的所有区间.对于左端点\(i∈[l, mid - 1]\),向左推并计算\([l,mid]\)范围内的最大\(/\)最小值. 然后右端 ...

  9. bzoj 3745: [Coci2015]Norma

    Description Solution 考虑分治: 我们要统计跨越 \(mid\) 的区间的贡献 分最大值和最小值所在位置进行讨论: 设左边枚举到了 \(i\),左边 \([i,mid]\) 的最大 ...

随机推荐

  1. 【Head First Servlets and JSP】笔记15:建立一个JSP页面来显示被访问了多少次

    1.这是一个非常简单的程序,它看起来是这个样子的: 实际功能就是,每访问该页面一次count数加1,在服务器重启前(JVM重启前),这个次数将持续累加. 2.因为这个程序过于简单,所以我希望可以通过H ...

  2. 编写自已的第一个MapReduce程序

    从进入系统学习到现在,貌似我们还没有真正开始动手写程序,估计有些立志成为Hadoop攻城狮的小伙伴们已经有些急了.环境已经搭好,小讲也有些按捺不住了.今天,小讲就和大家一起来动手编写我们的第一个Map ...

  3. 大话设计模式之PHP篇 - 适配器模式

    定义将一个类的接口转换成客户希望的另外一个接口,使用原本不兼容的而不能在一起工作的那些类可以在一起工作. 角色Target适配目标,该角色定义把其他类转换为何种接口,也就是我们的期望接口.Adapte ...

  4. time_t、pthread_t

    1.time_t实际上就是长整型long int;用来保存从1970年1月1日0时0分0秒到现在时刻的秒数!用time()这个函数获取! #ifndef __TIME_T #define __TIME ...

  5. Kubernetes Horizontal Pod Autoscaler

    非常牛逼的技术,目前最新的版本支持众多的Feature HPA功能需要Heapster收集的CPU.内存等数据作为支撑 配置示例: apiVersion: autoscaling/v2beta1 ki ...

  6. .NET CORE 动态调用泛型方法

    using System; using System.Reflection; namespace DynamicCall { class Program { static void Main(stri ...

  7. centos安装zabbix监控服务器端

    首先安装zabbx 依赖yum install net-snmp-devel libxml2-devel libcurl-devel -y 下载zabbix 源码包wget https://ncu.d ...

  8. 分布式任务调度平台XXL-Job集群版搭建

    如果集群: 保存后: 启动两个 job 第二个job的配置: # web port server.port=8082 # log config logging.config=classpath:log ...

  9. Luogu-1527 [国家集训队]矩阵乘法

    Luogu-1527 [国家集训队]矩阵乘法 题面 Luogu-1527 题解 昨天学CDQ分治时做了一些题,但是因为题(wo)太(tai)水(lan)了(le)并没有整理 学了一晚上的整体二分,拿这 ...

  10. UVA 11525 Permutation (树状数组+YY)

    题意:给你k个数Si,然后给你一个等式   H= ∑  Si ∗ (K − i)!  (i=(1->k)且0 ≤ Si ≤ K − i). 叫你求出第H个全排列 其实这是一个康托展开:X=a[n ...