「HNOI2016」序列
传送门
Description
有 \(q\) 个询问,每个询问给定两个数\(l\) 和\(r\),求 \(a[l:r]\) 的不同子序列的最小值之和
Solution
校内模拟赛用了这道题,但是莫队只能拿\(80\)分,正解是猫树
当然还是莫队啦
考虑一个数加入时的贡献,就是以它为端点的区间的贡献
发现可以将现有的区间分成一段一段的,每段的最小值不同
这个可以用单调栈\(+\)倍增解决
于是就有了\(O(n\sqrt n\log n)\)的做法
但是显然过不了原题
所以想办法把\(\log\)去掉
以右端点为例,令\(f[i]\)表示\(a_i\)对区间\([1,i-1]\)的贡献
发现答案可以看成是\(f[i]-f[k],(k\leq i)\)然后再加上\(k\)以后的贡献
但是,这里的\(k\)得满足它是端点之一,且它往左的贡献很好算
那是什么?就是区间最小值啦,它往左的贡献就是\(a[k]*(k-nowl+1)\)
所以可以先预处理所有的\(f[i]\),用\(RMQ\)算法\(O(1)\)求出区间最小值就行了
复杂度\(O(n\sqrt n)\)
附上不能看的代码
Code
#include<bits/stdc++.h>
#define ll long long
#define db double
#define dbg1(x) cerr<<#x<<"="<<(x)<<" "
#define dbg2(x) cerr<<#x<<"="<<(x)<<"\n"
#define dbg3(x) cerr<<#x<<"\n"
#define int ll
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int MN=1e5+5,Mod=1e9+7;
int A,B,C,P;
ll lastAns=0;
inline int rnd(){return A=(A*B+(C^(int)(lastAns&0x7fffffffll))%P)%P;}
int n,q,l,r,a[MN];
bool f1,f2;
namespace solve1
{
int L[MN],R[MN],st[MN],top;
void Main()
{
int i;
st[top=0]=0;
for(i=1;i<=n;++i)
{
while(top&&a[st[top]]>=a[i]) --top;
L[i]=st[top]+1;
st[++top]=i;
}
st[top=0]=n+1;
for(i=n;i;--i)
{
while(top&&a[st[top]]>a[i]) --top;
R[i]=st[top]-1;
st[++top]=i;
}
while(q--)
{
l=read(),r=read();
ll ans=0ll;
for(i=l;i<=r;++i)
ans+=1ll*a[i]*1ll*(min(r,R[i])-i+1)*1ll*(i-max(l,L[i])+1);
printf("%lld\n",ans);
}
}
}
ll suf1[MN],suf2[MN];
void init()
{
int i;suf1[n+1]=suf2[n+1]=0ll;
for(i=n;i;--i)
suf1[i]=suf1[i+1]+1ll*a[i]*(n-i+1),
suf2[i]=suf2[i+1]+a[i];
}
ll cal(int x,int y){return suf1[x]-suf1[y+1]-1ll*(suf2[x]-suf2[y+1])*1ll*(n-y);}
struct Ques{int l,r,id;}_[MN];int tt;
namespace solve2
{
int Bl,bel[MN],nowl,nowr;
ll ans[MN],Sum,nowans;
ll s1[20][MN],s2[20][MN],p1[20][MN],p2[20][MN],f[MN],g[MN];
bool cmp(Ques x,Ques y)
{
return bel[x.l]!=bel[y.l]?bel[x.l]<bel[y.l]
:(bel[x.l]&1?x.r<y.r:x.r>y.r);
}
int st[MN],top;
ll cal(int x,bool ty)
{
int tmp=0;
if(!ty)
{
for(int i=17;~i;--i)
if(s1[i][x]==nowr) return tmp+s2[i][x];
else if(s1[i][x]<nowr)tmp+=s2[i][x],x=s1[i][x]+1;
return tmp+1ll*a[x]*(nowr-x+1);
}
else
{
for(int i=17;~i;--i)
if(p1[i][x]==nowl) return tmp+p2[i][x];
else if(p1[i][x]>nowl)tmp+=p2[i][x],x=p1[i][x]-1;
return tmp+1ll*a[x]*(x-nowl+1);
}
}
int Log[MN],mi[20][MN];
int cmp_(int x,int y){return a[x]<a[y]?x:y;}
int gmin(int x,int y){int og=Log[y-x+1];return cmp_(mi[og][x],mi[og][y-(1<<og)+1]);}
void Init()
{
int i,j;
for(i=2;i<=n;++i) Log[i]=Log[i>>1]+1;
for(i=1;i<=n;++i) mi[0][i]=i;
for(j=1;j<18;++j)for(i=1;i<=n;++i)if(i-1+(1<<j)<=n)mi[j][i]=cmp_(mi[j-1][i],mi[j-1][i+(1<<j-1)]);
st[top=0]=0;
for(i=1;i<=n;++i)
{
while(top&&a[st[top]]>=a[i]) --top;
p1[0][i]=st[top]+1;
p2[0][i]=1ll*(i-p1[0][i]+1)*a[i];
st[++top]=i;
}
st[top=0]=n+1;
for(i=n;i;--i)
{
while(top&&a[st[top]]>a[i]) --top;
s1[0][i]=st[top]-1;
s2[0][i]=1ll*(s1[0][i]-i+1)*a[i];
st[++top]=i;
}
for(i=1;i<18;++i)
for(j=1;j<=n;++j)
{
if(s1[i-1][j]>=n) s1[i][j]=n+1;
else s1[i][j]=s1[i-1][s1[i-1][j]+1],
s2[i][j]=s2[i-1][j]+s2[i-1][s1[i-1][j]+1];
if(p1[i-1][j]<=1) p1[i][j]=0;
else p1[i][j]=p1[i-1][p1[i-1][j]-1],
p2[i][j]=p2[i-1][j]+p2[i-1][p1[i-1][j]-1];
}
nowl=1;nowr=n;
for(i=1;i<=n;++i) f[i]=cal(i,1),g[i]=cal(i,0);
}
ll Cal(int x,int ty)
{
ll tmp=0ll;
if(ty)
{
int pos=gmin(nowl,x);
tmp=f[x]-f[gmin(nowl,x)];
tmp+=1ll*a[pos]*(pos-nowl+1);
}
else
{
int pos=gmin(x,nowr);
tmp=g[x]-g[gmin(x,nowr)];
tmp+=1ll*a[pos]*(nowr-pos+1);
}
return tmp;
}
void Add(int x,bool ty){nowans+=Cal(x,ty);}
void Del(int x,bool ty){nowans-=Cal(x,ty);}
void Main()
{
Init();Bl=sqrt((db)(n));
for(int i=1;i<=n;++i)bel[i]=(i+Bl-1)/Bl;
std::sort(_+1,_+tt+1,cmp);
nowl=1,nowr=0;Sum=0;nowans=0;
for(int i=1;i<=tt;++i)
{
while(nowr<_[i].r) Add(++nowr,1);
while(nowl>_[i].l) Add(--nowl,0);
while(nowr>_[i].r) Del(nowr--,1);
while(nowl<_[i].l) Del(nowl++,0);
if(f2) (Sum+=nowans)%=Mod;
else ans[_[i].id]=nowans;
}
if(f2) printf("%lld\n",Sum);
else for(int i=1;i<=tt;++i) printf("%lld\n",ans[i]);
}
}
signed main()
{
n=read();q=read();
if(f2) A=read(),B=read(),C=read(),P=read();
int i;bool c1=1,c2=1;a[0]=-Mod;
for(i=1;i<=n;++i) a[i]=read(),c1&=(a[i]==a[1]),c2&=(a[i]>a[i-1]);
if(c2) init();
if(n*q<=Mod&&!f1&&!f2) {solve1::Main();return 0;}
while(q--)
{
if(f2)
{
l=rnd()%n+1;r=rnd()%n+1;
if(l>r)swap(l,r);
}
else if(f1)
{
l=read();r=read();
l=((l+lastAns)%n+n)%n+1;
r=((r+lastAns)%n+n)%n+1;
if(l>r)swap(l,r);
}
else l=read(),r=read();
if(c1) printf("%lld\n",lastAns=1ll*(1ll*(r-l+1)*1ll*(r-l+2)/2)*1ll*a[1]);
else if(c2) printf("%lld\n",lastAns=cal(l,r));
else _[++tt].l=l,_[tt].r=r,_[tt].id=tt;
}
if(!c1&&!c2){solve2::Main();return 0;}
return 0;
}
Blog来自PaperCloud,未经允许,请勿转载,TKS!
「HNOI2016」序列的更多相关文章
- 「HNOI2016」序列 解题报告
「HNOI2016」序列 有一些高妙的做法,懒得看 考虑莫队,考虑莫队咋移动区间 然后你在区间内部找一个最小值的位置,假设现在从右边加 最小值左边区间显然可以\(O(1)\),最小值右边的区间是断掉的 ...
- loj #2051. 「HNOI2016」序列
#2051. 「HNOI2016」序列 题目描述 给定长度为 n nn 的序列:a1,a2,⋯,an a_1, a_2, \cdots , a_na1,a2,⋯,an,记为 a[1: ...
- loj2051 「HNOI2016」序列
ref #include <algorithm> #include <iostream> #include <cstdio> #include <cmath& ...
- 「HNOI2016」数据结构大毒瘤
真是 \(6\) 道数据结构毒瘤... 开始口胡各种做法... 「HNOI2016」网络 整体二分+树状数组. 开始想了一个大常数 \(O(n\log^2 n)\) 做法,然后就被卡掉了... 发现直 ...
- Loj #3059. 「HNOI2019」序列
Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...
- 「HNOI2016」树 解题报告
「HNOI2016」树 事毒瘤题... 我一开始以为每次把大树的子树再接给大树,然后死活不知道咋做,心想怕不是个神仙题哦 然后看题解后才发现是把模板树的子树给大树,虽然思维上难度没啥了,但是还是很难写 ...
- 「HNOI2016」网络 解题报告
「HNOI2016」网络 我有一个绝妙的可持久化树套树思路,可惜的是,它的空间是\(n\log^2 n\)的... 注意到对一个询问,我们可以二分答案 然后统计经过这个点大于当前答案的路径条数,如果这 ...
- 「HNOI2016」最小公倍数 解题报告
「HNOI2016」最小公倍数 考虑暴力,对每个询问,处理出\(\le a,\le b\)的与询问点在一起的联通块,然后判断是否是一个联通块,且联通块\(a,b\)最大值是否满足要求. 然后很显然需要 ...
- AC日记——「SDOI2017」序列计数 LibreOJ 2002
「SDOI2017」序列计数 思路: 矩阵快速幂: 代码: #include <bits/stdc++.h> using namespace std; #define mod 201704 ...
随机推荐
- JavaScript前端和Java后端的AES加密和解密(转)
在实际开发项目中,有些数据在前后端的传输过程中需要进行加密,那就需要保证前端和后端的加解密需要统一.这里给大家简单演示AES在JavaScript前端和Java后端是如何实现加密和解密的. java端 ...
- php数组的数学功能相关常用函数
php数组中有一些函数与数学相关的函数,大多都是以array开头然后下划线接一个数学上的英文单词,如下: array_diff() array_diff_assoc() array_intersect ...
- iOS - 崩溃异常处理(1)
https://www.jianshu.com/p/4d32664dcfdb 一.关于崩溃 闪退估计是我们最不想看到的,对于用户而言,马上就能产生一种不悦,对于投资方而言,也会产生对技术实力的不信任感 ...
- JUC - ThreadPoolExecutor
JUC - ThreadPoolExecutor 创建一个ThreadPoolExecutor ThreadPoolExecutor( int corePoolSize, // 保留在池中的线程数,即 ...
- Vue学习之webpack中使用vue(十七)
一.包的查找规则: 1.在项目根目录中找有没有 node_modules 的文件夹: 2.在 node_modules 中根据包名,找对应的vue 文件夹: 3.在vue 文件夹中,找 一个叫做 pa ...
- XML整形以及改行字符串输出
XML整形 估计如下一样使用XDocument的人比较多,毕竟也是微软推荐使用的. string FormatXml(string Xml) { try { XDocument doc = XDocu ...
- python测试开发django-43.xadmin添加小组件报错解决
前言 xadmin首页上有个添加小组件按钮,打开的时候会报错“render() got an unexpected keyword argument 'renderer'”环境:python3.6dj ...
- 云计算与大数据实验:Hbase shell操作用户表
[实验目的] 1)了解hbase服务 2)学会hbase shell命令操作用户表 [实验原理] HBase是一个分布式的.面向列的开源数据库,它利用Hadoop HDFS作为其文件存储系统,利用Ha ...
- 【转】高性能网络编程6--reactor反应堆与定时器管理
反应堆开发模型被绝大多数高性能服务器所选择,上一篇所介绍的IO多路复用是它的实现基础.定时触发功能通常是服务器必备组件,反应堆模型往往还不得不将定时器的管理囊括在内.本篇将介绍反应堆模型的特点和用法. ...
- Principle如何制作动效设计?简单易学的Principle动效设计教程
Principle for Mac是一款新开发的交互设计软件.相比 Pixate 更容易上手,界面类似 Sketch 等做图软件,思路有点像用 Keynote 做动画,更「可视化」一些. 如果您还没有 ...