P9461 「EZEC-14」众数 II
题意
略。
思路
发现如果区间包含的 \(a_i\) 都是完整的,那么最小众数一定是 \(1\)。
否则如果 \(a_l\) 只有一段后缀 \([x,a_l]\) 和 \(a_r\) 只有一段前缀 \([1,y]\),当且仅当 \(\forall i \in [l,r], a_i \ge x\) 时最小众数是 \(x\),否则还是 \(1\)。
没有其他情况。
为了方便,我们转为求出所有最小众数为 \(x(x>1)\) 的子区间,贡献 \(x-1\)。
然后所有子区间再贡献一个 \(1\)。这部分显然是好求的。
\(\forall i \in [l,r], a_i \ge x\) 这个条件,让我们想到小根笛卡尔树。
对于笛卡尔树上一个节点 \(u\),在它的左子树取一个 \(l\),右子树取一个 \(r\),计算贡献。显然这样的子区间最小众数为 \(x \in [1,a_u]\)。
这里最小众数为 \(x\) 的时候有几个子区间?
左端点可以取左子树上任意一个点或者点 \(u\) 的高度 \(x\) 的位置,有 \(siz_{ls} +1\) 种方案。
右端点可以取右子树上任意一个点或者点 \(u\) 的高度 \(\ge x\) 的位置,有 \((sum_{rs}+a_u) - (x-1)(siz_{rs}+1)\) 种方案。
每个方案的贡献是 \(x-1\)。
所以 \(u\) 的子树的总贡献是:
\[\sum_{x=1}^{a_u} (x-1) (siz_{ls}+1) ((sum_{rs}+a_u)-(x-1)(siz_{rs}+1)) \]
化简一下,变成:
\[\begin{aligned} & (siz_{ls}+1) \sum_{x=1}^{a_u} (sum_{rs}+a_u) (x-1) -(siz_{rs}+1)(x-1)^2 \\ = & (siz_{ls}+1) ((sum_{rs}+a_u) (\sum_{x=1}^{a_u-1} x) - (siz_{rs}+1) (\sum_{x=1}^{a_u-1} x^2)) \\ = & (siz_{ls}+1) ((sum_{rs}+a_u)\frac{a_u(a_u-1)}2 - (siz_{rs}+1) \frac{(a_u-1)a_u(2a_u-1)}{6}) \end{aligned} \]
是不是做完了。
可以线性做,但是单 \(\log\) 可以少写点东西。
code
cpp
#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
namespace wing_heart {
constexpr int N=1e6+7,mod=998244353,V=1e6;
struct modint {
int x;
modint (int y=0) : x(y) {}
modint operator + (modint b) const { return x+b.x<mod ? x+b.x : x+b.x-mod; }
modint operator - (modint b) const { return x-b.x<0 ? x-b.x+mod : x-b.x; }
modint operator * (modint b) const { return 1ll*x*b.x%mod; }
modint &operator += (modint b) { return *this = *this + b; }
modint &operator *= (modint b) { return *this = *this * b; }
};
int n,a[N];
int tr[N];
void add(int x,int w) {
for(;x<=V;x+=x&-x) tr[x]=max(tr[x],w);
}
int ask(int x) {
int s=0;
for(;x;x-=x&-x) s=max(s,tr[x]);
return s;
}
modint b[N];
int lt[N],rt[N];
modint ans;
void main() {
sf("%d",&n);
rep(i,1,n) sf("%d",&a[i]), b[i]=b[i-1]+a[i];
rep(i,1,n) {
lt[i]=ask(a[i])+1;
add(a[i],i);
}
memset(tr,0,sizeof(tr));
per(i,n,1) {
rt[i]=n-ask(a[i]-1);
add(a[i],n-i+1);
}
// rep(i,1,n) pf("%d %d\n",lt[i],rt[i]);
rep(i,1,n) ans+=((b[rt[i]]-b[i-1])*(1ll*a[i]*(a[i]-1)/2%mod)-(modint)(rt[i]-i+1)*(1ll*(a[i]-1)*a[i]*(2*a[i]-1)/6%mod))*(i-lt[i]+1);
ans+=b[n]+(1ll*b[n].x*(b[n].x-1)/2%mod);
pf("%d\n",ans.x);
}
}
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("my.out","w",stdout);
#endif
wing_heart :: main();
}