[ARC177D] Earthquakes 题解
[ARC177D] Earthquakes
单调栈好题。
题面不短,给了我们很多限制。一定要理清思路,挨个来解决这些限制。
首先可以确定的是,先把所有电线杆按照位置而不是倒塌时间来排序。现在我们定义第 \(i\) 个电线杆是从左往右数第 \(i\) 个电线杆,每个电线杆的倒塌时间是 \(x_i\)。
容易发现,电线杆可以分成若干个段,使得同一个段内的电线杆之间的距离全部小于 \(H\)。这样的话段与段之间肯定是互不影响的,我们只需考虑同一个段内的情况,最后合并答案即可。
每个段内的情况
要使得这个段内的电线杆全部倒塌,考虑转化一下,求出第 \(i\) 个电线杆是最后主动倒塌的概率,其实和原问题是等价的。(“主动” 指不被其它电线杆碰倒的倒塌)
显然,一个段能被分成三部分:向左倒塌的一部分、站着的一部分、向右倒塌的一部分。
那么要使第 \(i\) 个电线杆最后主动倒下,当且仅当它是那站着的一部分的左端点或右端点。用官解的图来说就是类似这样(不过它只画了一个电线杆):

补充:下文所说 “前缀/后缀最小值数量” 的意义为:找到向左/向右第一个小于 \(x_i\) 的位置,这个位置所代表的前缀/后缀长度。
这种情况等价于(设当前位置为 \(p\)):
- \(\forall i\in[1,p-1]\),其前缀 \(1\sim i\) 的最小值的位置都向左倒塌;
- \(\forall i\in[p+1,n]\),其后缀 \(i\sim n\) 的最小值的位置都向右倒塌。这里的 \(n\) 是这个段的电线杆数量。
所有前缀最小值和后缀最小值如果都按我们希望的方向倒塌,这个概率是 \(\dfrac1{2^{\mathit{cnt}}}\),其中 \(\mathit{cnt}\) 是这个点的前缀最小值和后缀最小值的数量之和。此外还有一些特殊情况需要处理。当 \(n=1\) 时,当前点向左还是向右倒无所谓,所以概率就是上面的那个东西;当 \(i=1\) 或 \(i=n\) 或当前点有某个相邻的点的 \(x\) 值比他大,当前点的倒塌方向是固定的,所以概率需要再乘 \(1/2\)。
现在子问题就解决了。我们最终得到了每一段的每根电线杆最后一个倒塌的概率。
合并答案
一共有 \(\mathit{tot}\) 段,电线杆 \(i\) 所在段的编号为 \(\text{idx}(i)\),则第 \(t\) 个电线杆的答案就是:
其中 \(s_i\) 是第 \(i\) 段最后倒下的电线杆编号小于 \(t\) 的概率之和。
考虑按照时间逐个添加点,那这个问题就是一个单点加、区间求乘积的问题,上线段树即可。
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
#define inv(x) power(x,MOD-2)
#define fs first
#define sc second
using namespace std;
char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
template<typename T>
void write(T x,char sf='\n'){
if(x<0)putchar('-'),x=~x+1;
int top=0;
do str[top++]=x%10,x/=10;while(x);
while(top)putchar(str[--top]+48);
if(sf^'#')putchar(sf);
}
using ll=long long;
constexpr int MAXN=2e5+5;
constexpr ll MOD=998244353;
int n,h,idx[MAXN],tot,p[MAXN];
int stk[MAXN],top;
ll pw[MAXN]={1};
vector<pair<int,int>>v;
vector<int>a[MAXN];
vector<ll>res[MAXN];
ll power(ll a,int b){
ll res=1;
for(;b;a=a*a%MOD,b>>=1)if(b&1)res=res*a%MOD;
return res;
}
struct{
#define lp p<<1
#define rp p<<1|1
ll st[MAXN<<2];
void chg(int x,ll k,int s=1,int t=tot,int p=1){
if(s==t) return st[p]=(st[p]+k)%MOD,void();
int mid=(s+t)>>1;
if(x<=mid) chg(x,k,s,mid,lp);
else chg(x,k,mid+1,t,rp);
st[p]=st[lp]*st[rp]%MOD;
}
ll ask(int l,int r,int s=1,int t=tot,int p=1){
if(l<=s&&t<=r) return st[p];
int mid=(s+t)>>1;
if(l>mid) return ask(l,r,mid+1,t,rp);
if(mid>=r) return ask(l,r,s,mid,lp);
return ask(l,r,s,mid,lp)*ask(l,r,mid+1,t,rp)%MOD;
}
}T;
void ins(int x,bool fl){
if(fl) tot++;
idx[x]=tot;
a[tot].emplace_back(x);
p[x]=a[tot].size()-1;
}
void solve(int id,vector<int>&a){
static int cnt[MAXN];
int n=a.size()-1;
top=0;
for(int i=1;i<=n;i++){
while(top&&a[stk[top]]>a[i]) top--;
cnt[i]=top;
stk[++top]=i;
}
top=0;
for(int i=n;i;i--){
while(top&&a[stk[top]]>a[i]) top--;
cnt[i]+=top;
stk[++top]=i;
}
res[id].resize(1);
for(int i=1;i<=n;i++){
int tp=0;
if(i==1||a[i-1]<a[i]) tp++;
if(i==n||a[i+1]<a[i]) tp++;
res[id].emplace_back(tp*pw[n-cnt[i]-1]%MOD);
}
}
int main(){
n=read(),h=read();
for(int i=1;i<=n;i++){
pw[i]=(pw[i-1]<<1)%MOD;
v.emplace_back(read(),i);
a[i].resize(1);
}
sort(v.begin(),v.end());
ins(v.begin()->sc,1);
for(auto it=v.begin()+1;it!=v.end();it++) ins(it->sc,it->fs-prev(it)->fs>h);
for(int i=1;i<=tot;i++) solve(i,a[i]);
for(int i=1;i<=n;i++){
ll ans=1;
if(idx[i]>1) ans=T.ask(1,idx[i]-1);
if(idx[i]<tot) ans=ans*T.ask(idx[i]+1,tot)%MOD;
ans=ans*res[idx[i]][p[i]]%MOD;
T.chg(idx[i],res[idx[i]][p[i]]);
write(ans,' ');
}
return putchar('\n'),fw,0;
}

浙公网安备 33010602011771号