题解:P16313 [ICPC 2023 Jinan R] 向未来说你好

更差的阅读体验


某一天调这道题调到了 0:22,特此记录。


首先考虑静态情形,也就是没有 \(a_i\) 被修改的情况。

那么这个问题就是 [PA 2014] Druzyny 的弱化版,可以用类似地方法解决。具体地,我们假设 \(f_i\) 表示将 \([1, i]\) 分段地方案数,有转移

\[f_i = \sum_{j} \left[j < i \land i - j \ge \max\{a_{j+1}, a_{j+2}, \cdots, a_i\}\right] \cdot f_i \]

转移不连续,一般手法不太好优化,因此考虑 cdq 分治。每次处理 \([l, r]\) 的 dp 值,记 \(mid\) 为区间中点,则只考虑 \([l, mid]\)\(j\)\([mid+1, r]\)\(i\) 的贡献。记 \(ml_j\) 表示 \([j, mid]\) 上的最大值,\(mr_i\) 表示 \([mid+1, i]\) 上的最大值。则一个 \(j\) 可以对一个 \(i\) 产生贡献可以写成 \(i - j \ge \max\{ml_{j+1}, mr_i\}\)

拆掉 \(\max\) 可以得到以下两个式子:

  • \(i - j \ge ml_{j+1}\)\(i \ge \color{red}j + ml_{j+1}\)
  • \(i - j \ge mr_i\)\(i - mr_i \ge \color{red} j\)

由上可以发现,我们把每个 \(j\) 看作一个二维平面上的点 \((j + ml_{j+1}, j)\),则会对一个特定 \(i\) 产生影响的 \(j\) 位于一个矩形中。因此可以通过扫描线求解二位数点,来完成 \(j\)\(i\) 的转移。


接下来考虑如何计算把一个 \(a_k\) 置于 \(1\) 后的影响。我们直接思考在原先的 \(f_n\) 基础上的增量。

那么我们用求 \(f\) 完全一样的方案求出一个 \(g_i\) 表示 \([i, n]\) 的分段方案数。将 \(a_k\) 置为 \(1\) 后,应该多出一些包含 \(k\) 的合法的段。

现在考虑一个段 \((j, i]\),容易发现,如果 \((j, i]\) 变成了一个合法的段,则会新增 \(f_j \cdot g_{i+1}\) 种分段方案。这一段会被计算为新增贡献,首先要满足这一段在 \(a_k\) 置于 \(1\) 之前是不合法的,也就是 \(i - j < \max\{a_{j+1}, a_{j+2}, \cdots, a_i\}\)。然后,将 \(a_k\) 赋值为 \(1\) 后这一段变合法了,则说明 \(a_k\) 是区间内唯一的最大值,而修改后区间的最大值变为了原区间的严格次大值,也就是 \(i - j \ge \operatorname{2^{nd}-max} \{a_{j+1}, a_{j+2}, \cdots, a_i\}\)。容易发现一个 \((j, i]\) 会贡献到的 \(k\) 是唯一的。这启发我们,仍然通过分治计算新增的贡献。

仍旧对于区间 \([l, r]\),仅考虑 \([l, mid]\)\(j\)\([mid+1, r]\)\(i\) 产生的新增贡献。接下来将要讨论 \((j, i]\) 的最大值是在 \((j, mid]\) 还是在 \([mid+1, r]\) 两种情况,为减少篇幅,仅考虑最大值在 \((j, mid]\) 的情况。

则记 \(ml_j\) 表示 \([j, mid]\) 的最大值,\(ml2_j\) 表示 \([j, mid]\) 的次大值,\(mr_i\) 表示 \([mid+1, r]\) 的最大值。则要满足以下两个条件:

  • \(i - j < \max\{ml_{j+1}, mr_{i}\}\)
  • \(i - j \ge \max\{ml2_{j+1}, mr_{i}\}\)

由第二个不等式,可以得到

  • \(i - j \ge ml2_{j+1}\)\(ml2_{j+1} + j \le \color{red}i\)
  • \(i - j \ge mr_i\)\(j \le \color{red}i - mr_i\)

此时在第一个式子中 \(i - j < mr_i\) 已经不成立,因此只有

  • \(i - j < ml_{j+1}\)\(ml_{j+1} + j > \color{red}i\)

由上述三个式子,可以发现,如果把每个 \(i\) 看作平面上的一个点 \((i, i - mr_i)\),则对每个 \(j\) 有贡献的 \(i\) 一定在二维平面上的一个矩形内!因此对于一个 \(j\),所有 \(i\) 的贡献之和同样可以通过扫描线计算出。而由于最大值位于 \((j, mid]\) 上,因此一个 \(j\) 对应的 \(k\)(也就是对 \(a\) 修改的位置)也是唯一的,因此直接将这个 \(j\) 的贡献累加到对应 \(k\) 上的答案即可!

最大值属于 \([mid+1, i]\) 区间的情况是完全对称的,这里不再赘述。

那么这道题就做完了,由于外层分治带一个 \(\log\),内层二维数点也带一个 \(\log\),因此总复杂度为 \(O(n \log^2 n)\)

#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;
}
posted @ 2026-07-20 23:08  dyc2022  阅读(4)  评论(0)    收藏  举报
/* 设置动态特效 */ /* 设置文章评论功能 */ 返回顶端 levels of contents