题解:P16313 [ICPC 2023 Jinan R] 向未来说你好
更好的阅读体验
某一天调这道题调到了 0:22,特此记录。
首先考虑静态情形,也就是没有
那么这个问题就是 [PA 2014] Druzyny 的弱化版,可以用类似地方法解决。具体地,我们假设
转移不连续,一般手法不太好优化,因此考虑 cdq 分治。每次处理
拆掉
由上可以发现,我们把每个
接下来考虑如何计算把一个
那么我们用求
现在考虑一个段
仍旧对于区间
则记
由第二个不等式,可以得到
此时在第一个式子中
由上述三个式子,可以发现,如果把每个
最大值属于
那么这道题就做完了,由于外层分治带一个
#include<bits/stdc++.h>
#define endl '\n'
#define N 400006
#define MOD 998244353
using namespace std;
inline void add(int &x,int y) {x+=y,x-=x>=MOD?MOD:0;}
inline void dec(int &x,int y) {x+=MOD-y,x-=x>=MOD?MOD:0;}
// mx_l[j+1] + j <= i
// i - j >= mx_r[i]
// j <= i - mx_r[i]
int n,a[N],f[N],g[N],mx_l[N],mxpos[N],mx2_l[N],mx_r[N],mx2_r[N],ans[N];
int bn,b[N];
vector<int> vec[N];
struct BIT {
int tree[N];
void upd(int k,int x) {for(;k<=n+1;k+=k&-k)add(tree[k],x);}
int query(int k)
{
int ret=0;
for(;k;k-=k&-k)add(ret,tree[k]);
return ret;
}
int query(int l,int r)
{
if(l>r||l>n+1||r<1)return 0;
l=max(1,l),r=min(n+1,r);
return (query(r)-query(l-1)+MOD)%MOD;
}
} T;
void cdq1(int l,int r,int *dp)
{
if(l==r)return;
int mid=l+r>>1;
cdq1(l,mid,dp);
bn=0,mx_l[mid+1]=mx_r[mid]=-2e9;
for(int i=mid;i>=l;i--)mx_l[i]=max(mx_l[i+1],a[i]);
for(int i=mid+1;i<=r;i++)mx_r[i]=max(mx_r[i-1],a[i]);
for(int j=l;j<=mid;j++)b[++bn]=j+mx_l[j+1];
for(int i=mid+1;i<=r;i++)b[++bn]=i;
sort(b+1,b+1+bn),bn=unique(b+1,b+1+bn)-b-1;
for(int i=1;i<=bn;i++)vec[i].clear();
for(int j=l;j<=mid;j++)
{
int id=lower_bound(b+1,b+1+bn,j+mx_l[j+1])-b;
vec[id].push_back(j);
}
vector<pair<int,int> > change;
for(int x=1;x<=bn;x++)
{
for(int j:vec[x])
T.upd(j+1,dp[j]),change.push_back({j,dp[j]});
if(b[x]>mid&&b[x]<=r)
{
int i=b[x];
if(i-mx_r[i]>=0)add(dp[i],T.query(i-mx_r[i]+1));
}
}
for(auto [x,y]:change)T.upd(x+1,(MOD-y)%MOD);
cdq1(mid+1,r,dp);
}
void cdq2(int l,int r)
{
if(l==r)return;
int mid=l+r>>1;
cdq2(l,mid);
bn=0,mx_l[mid+1]=mx2_l[mid+1]=-2e9,
mx_r[mid]=mx2_r[mid]=-2e9;
for(int j=mid;j>=l;j--)
{
mxpos[j]=mxpos[j+1];
mx_l[j]=mx_l[j+1],mx2_l[j]=mx2_l[j+1];
if(a[j]>=mx_l[j])mx2_l[j]=mx_l[j],mx_l[j]=a[j],mxpos[j]=j;
else if(a[j]>mx2_l[j])mx2_l[j]=a[j];
}
for(int i=mid+1;i<=r;i++)
{
mxpos[i]=mxpos[i-1];
mx_r[i]=mx_r[i-1],mx2_r[i]=mx2_r[i-1];
if(a[i]>=mx_r[i])mx2_r[i]=mx_r[i],mx_r[i]=a[i],mxpos[i]=i;
else if(a[i]>mx2_r[i])mx2_r[i]=a[i];
}
for(int i=mid+1;i<=r;i++)b[++bn]=i-mx_r[i];
for(int j=l;j<=mid;j++)b[++bn]=j;
sort(b+1,b+1+bn),bn=unique(b+1,b+1+bn)-b-1;
for(int i=1;i<=bn;i++)vec[i].clear();
for(int i=mid+1;i<=r;i++)
{
int id=lower_bound(b+1,b+1+bn,i-mx_r[i])-b;
vec[id].push_back(i);
}
vector<pair<int,int> > change;
for(int x=bn;x;x--)
{
for(int i:vec[x])
T.upd(i+1,g[i+1]),change.push_back({i,g[i+1]});
if(b[x]>=l&&b[x]<=mid)
{
int j=b[x],val=T.query(j+mx2_l[j+1]+1,j+mx_l[j+1]);
if(val)add(ans[mxpos[j+1]],1ll*f[j]*val%MOD);
}
}
for(auto [x,y]:change)T.upd(x+1,(MOD-y)%MOD);
change.clear(),bn=0;
for(int j=l;j<=mid;j++)b[++bn]=j+mx_l[j+1];
for(int i=mid+1;i<=r;i++)b[++bn]=i;
sort(b+1,b+1+bn),bn=unique(b+1,b+1+bn)-b-1;
for(int i=1;i<=bn;i++)vec[i].clear();
for(int j=l;j<=mid;j++)
{
int id=lower_bound(b+1,b+1+bn,j+mx_l[j+1])-b;
vec[id].push_back(j);
}
for(int x=1;x<=bn;x++)
{
for(int j:vec[x])
T.upd(j+1,f[j]),change.push_back({j,f[j]});
if(b[x]>mid&&b[x]<=r)
{
int i=b[x],val=T.query(i-mx_r[i]+2,i-mx2_r[i]+1);
if(val)add(ans[mxpos[i]],1ll*g[i+1]*val%MOD);
}
}
for(auto [x,y]:change)T.upd(x+1,(MOD-y)%MOD);
cdq2(mid+1,r);
}
main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
f[0]=1,cdq1(0,n,f),reverse(a+1,a+1+n);
g[0]=1,cdq1(0,n,g),reverse(a+1,a+1+n);
reverse(g,g+2+n);
for(int i=1;i<=n;i++)ans[i]=f[n];
cdq2(0,n);
for(int i=1;i<=n;i++)
printf("%d%c",ans[i]," \n"[i==n]);
return 0;
}