[ARC177D] Earthquakes 题解
[ARC177D] Earthquakes
单调栈好题。
题面不短,给了我们很多限制。一定要理清思路,挨个来解决这些限制。
首先可以确定的是,先把所有电线杆按照位置而不是倒塌时间来排序。现在我们定义第
容易发现,电线杆可以分成若干个段,使得同一个段内的电线杆之间的距离全部小于
每个段内的情况
要使得这个段内的电线杆全部倒塌,考虑转化一下,求出第
显然,一个段能被分成三部分:向左倒塌的一部分、站着的一部分、向右倒塌的一部分。
那么要使第
补充:下文所说 “前缀/后缀最小值数量” 的意义为:找到向左/向右第一个小于
的位置,这个位置所代表的前缀/后缀长度。
这种情况等价于(设当前位置为
,其前缀 的最小值的位置都向左倒塌; ,其后缀 的最小值的位置都向右倒塌。这里的 是这个段的电线杆数量。
所有前缀最小值和后缀最小值如果都按我们希望的方向倒塌,这个概率是
现在子问题就解决了。我们最终得到了每一段的每根电线杆最后一个倒塌的概率。
合并答案
一共有
其中
考虑按照时间逐个添加点,那这个问题就是一个单点加、区间求乘积的问题,上线段树即可。
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】