题解:P10764 [BalticOI 2024] Wall
美妙模拟赛拉原题。
给一个码量大点但是无脑的思路。
容易发现答案是 \(\sum\limits_{\forall h\{n\}}\sum\limits_{i=1}^n\min(pre_i,nxt_i)-h_i\),其中 \(pre_i,nxt_i\) 分别为 \(i\) 的前/后缀最大值。
因为 \(\min(pre_i,nxt_i)=pre_i+nxt_i-\max(pre_i,nxt_i)=pre_i+nxt_i-maxn\),所以原式又等于 \((\sum\limits_{\forall h\{n\}}\sum\limits_{i=1}^npre_i)+(\sum\limits_{\forall h\{n\}}\sum\limits_{i=1}^nnxt_i)-(\sum\limits_{\forall h\{n\}}\sum\limits_{i=1}^nmaxn)-(\sum\limits_{\forall h\{n\}}\sum\limits_{i=1}^nh_i)\)。
我们考虑分开算这四个东西:
-
\((\sum\limits_{\forall h\{n\}}\sum\limits_{i=1}^nh_i)\) 在读入时处理,不讲。
-
\((n\sum\limits_{\forall h\{n\}}maxn)\) 考虑求 \(\sum\limits_{i=1}^{\inf}\sum\limits_{\forall h\{n\}}[i\le maxn]\)。具体地,我们考虑每个位置有多少选择是小于 \(i\) 的,全部乘起来容斥掉即可。
-
\((\sum\limits_{\forall h\{n\}}\sum\limits_{i=1}^npre_i),(\sum\limits_{\forall h\{n\}}\sum\limits_{i=1}^nnxt_i)\) 这两个等价,沿用上面的思路,我们考虑求 \(\sum\limits_{i=1}^{\inf}\sum\limits_{\forall h\{n\}}\sum\limits_{i=1}^n[i\le pre_i]\),我们设 \(f_{i,0/1}\) 表示长度为 \(i\) 的前缀最大值是否不小于 \(i\) 的方案数最终的数量就是 \(\sum\limits_{i=1}^nf_{i,1}\times 2^{n-i}\),我们考虑一个位置 \(x\):
- 如果 \(a_x,b_x\) 都小于 \(i\),有 \(\begin{cases}f_{i,0}=2f_{i-1,0}\\f_{i,1}=2f_{i-1,1}\end{cases}\)。
- 如果 \(a_x,b_x\) 只有一个小于 \(i\),有 \(\begin{cases}f_{i,0}=f_{i-1,0}\\f_{i,1}=f_{i-1,0}+2f_{i-1,1}\end{cases}\)。
- 如果 \(a_x,b_x\) 都不小于 \(i\),有 \(\begin{cases}f_{i,0}=0\\f_{i,1}=2f_{i-1,0}+2f_{i-1,1}\end{cases}\)。
容易发现这个可以用线段树维护转移矩阵实现。
恶臭的代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
char buf[1000005],*p1,*p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
int read(){
int x=0,f=0,c=gc();
while(!isdigit(c))f|=(c=='-'),c=gc();
while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=gc();
return f?-x:x;
}
const int mod=1e9+7;
int n,a[500005],b[500005];
struct node{
int x,id;
bool operator<(const node &t)const{return x<t.x;}
}x[1000005];
namespace Sol1{//算maxn
struct ST{
struct Node{
int l,r,val;
}c[2000005];
void Build(int q,int l,int r){
c[q].l=l;c[q].r=r;
if(l==r){
c[q].val=0;
return;
}
int mid=l+r>>1;
Build(q<<1,l,mid);
Build(q<<1|1,mid+1,r);
c[q].val=c[q<<1].val*c[q<<1|1].val%mod;
}
void Change(int q,int x,int y){
if(c[q].l==c[q].r){
c[q].val+=y;
return;
}
int mid=c[q].l+c[q].r>>1;
if(x<=mid)Change(q<<1,x,y);
else Change(q<<1|1,x,y);
c[q].val=c[q<<1].val*c[q<<1|1].val%mod;
}
}T;
int main(){
int tot=0;
for(int i=1;i<=n;i++)x[++tot]=node({a[i],i}),x[++tot]=node({b[i],i});
sort(x+1,x+tot+1);
int Pow=1;
for(int i=1;i<=n;i++)Pow=Pow*2%mod;
int res=0;
int las=0;
T.Build(1,1,n);
for(int i=1;i<=tot;i++){
res=(res+(x[i].x-las+mod)%mod*(Pow-T.c[1].val+mod)%mod)%mod;
T.Change(1,x[i].id,1);
las=x[i].x;
}
return res;
}
}
namespace Sol2{//算前缀
struct M{
int a[2][2];
M(int op=0){
a[0][0]=a[1][1]=op;
a[1][0]=a[0][1]=0;
}
M operator+(const M &t)const{
M res;
res.a[0][0]=(a[0][0]+t.a[0][0])%mod;
res.a[0][1]=(a[0][1]+t.a[0][1])%mod;
res.a[1][0]=(a[1][0]+t.a[1][0])%mod;
res.a[1][1]=(a[1][1]+t.a[1][1])%mod;
return res;
}
M operator*(const M &t)const{
M res;
res.a[0][0]=(a[0][0]*t.a[0][0]+a[0][1]*t.a[1][0])%mod;
res.a[0][1]=(a[0][0]*t.a[0][1]+a[0][1]*t.a[1][1])%mod;
res.a[1][0]=(a[1][0]*t.a[0][0]+a[1][1]*t.a[1][0])%mod;
res.a[1][1]=(a[1][0]*t.a[0][1]+a[1][1]*t.a[1][1])%mod;
return res;
}
M operator*(const int &x)const{
M res;
res.a[0][0]=a[0][0]*x%mod;
res.a[0][1]=a[0][1]*x%mod;
res.a[1][0]=a[1][0]*x%mod;
res.a[1][1]=a[1][1]*x%mod;
return res;
}
}A0,A1,A2;
int Pow[500005];
struct ST{
struct Node{
int l,r;
M val,sum;
}c[2000005];
void up(int q){
int mid=c[q].l+c[q].r>>1;
c[q].val=c[q<<1].val*c[q<<1|1].val;
c[q].sum=(c[q<<1].sum*Pow[c[q].r-mid])+(c[q<<1].val*c[q<<1|1].sum);
}
void Build(int q,int l,int r){
c[q].l=l;c[q].r=r;
if(l==r){
c[q].val=c[q].sum=A2;
return;
}
int mid=c[q].l+c[q].r>>1;
Build(q<<1,l,mid);
Build(q<<1|1,mid+1,r);
up(q);
}
void Change(int q,int x,const M &y){
if(c[q].l==c[q].r){
c[q].val=c[q].sum=y;
return;
}
int mid=c[q].l+c[q].r>>1;
if(x<=mid)Change(q<<1,x,y);
else Change(q<<1|1,x,y);
up(q);
}
}T;
int sss[500005];
int main(){
A0.a[0][0]=2;A0.a[0][1]=0;
A0.a[1][0]=0;A0.a[1][1]=2;
A1.a[0][0]=1;A1.a[0][1]=1;
A1.a[1][0]=0;A1.a[1][1]=2;
A2.a[0][0]=0;A2.a[0][1]=2;
A2.a[1][0]=0;A2.a[1][1]=2;
Pow[0]=1;
for(int i=1;i<=n;i++)Pow[i]=Pow[i-1]*2%mod,sss[i]=2;
int tot=0,res=0;
for(int i=1;i<=n;i++)x[++tot]=node({a[i],i}),x[++tot]=node({b[i],i});
sort(x+1,x+tot+1);
T.Build(1,1,n);
for(int i=1;i<=tot;i++){
res=(res+(x[i].x-x[i-1].x)%mod*T.c[1].sum.a[0][1]%mod)%mod;
sss[x[i].id]--;
if(sss[x[i].id]==1)T.Change(1,x[i].id,A1);
else T.Change(1,x[i].id,A0);
}
return res;
}
}
signed main()
{
n=read();
int sum=0;
for(int i=1;i<=n;i++)a[i]=read(),sum=(sum+a[i])%mod;
for(int i=1;i<=n;i++)b[i]=read(),sum=(sum+b[i])%mod;
for(int i=1;i<n;i++)sum=sum*2%mod;
int sss=Sol1::main()*n%mod;
int ss=Sol2::main();
for(int i=1;i+i<=n;i++)swap(a[i],a[n-i+1]),swap(b[i],b[n-i+1]);
ss=(ss+Sol2::main());
printf("%lld",(ss-sum-sss+mod+mod)%mod);
return 0;
}