1 条题解
-
0
自动搬运
来自洛谷,原作者为

Supor__Shoep
AFO | 耳畔之际,恋之回音。 | 你的她,青春永驻搬运于
2025-08-24 22:57:41,当前版本为作者最后更新于2024-05-04 16:46:30,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
就我觉得 T3 比 T4 简单吗QAQ首先有一个非常常规的思路:枚举每一个数,求出其作为最大值的区间个数。这道题也是如此。
如果最终的序列 长度够小,那么我们可以利用单调栈得出每一个数 向前和向后的第一个 的数 和 ,如果找不到则分别为 ,那么 作为最大值的区间就有 个。
但是需要注意,有的区间是会被算重的,比如 ,两个 分别计算得到的区间都包含 。这个时候考虑更改 的定义为向前找到的第一个 的数的下标,如果找不到则为 ,计算方式仍然是 。这样就可以保证不会重复计算了,原因显然,因此把它当成一个 Trick 掌握就行了。
但是出题人非常可爱啊!这个 的长度可以达到 ,不可能直接计算。但是 的范围倒是很合理。这就说明我们要找到 序列的计算规律。
我们将 视为 个形如 的子段前后拼接得到的序列,记 表示第 个子段中的第 个数在 中的下标。
先考虑 的代价该怎么计算。由于各个子段的单调性,我们可以知道其向前能够找到的第一个 的数的下标一定是 (),向后能够找到的第一个 的数的下标一定是 (,注意是 而不是 )。可以发现 是 向前第一个大于等于它的数, 是 向后第一个大于它的数。可以通过这个结论,利用单调栈找到 。我们找到这两个 记为 (如果不存在满足条件的 或 ,则分别变为 ),则 的区间个数就是 $(s_{i,b_i}-s_{L(i),b_{L(i)}})(s_{R(i),b_{i}+1}-s_{i,b_i})$,可以利用 的前缀和解决。
我们记 ,那么:
$$(s_{i,b_i}-s_{L(i),b_{L(i)}})(s_{R(i),b_{i}+1}-s_{i,b_i})=(sum_i-sum_{L(i)})(sum_{R(i)-1}-sum_i+1+[R(i)\leq n]) $$每一个子段的顶点值我们就算完了,我们考虑将这种做法拓展到其它数上面。其实我们可以利用图像去思考:

我们知道对于每一个数,要去找前面和后面比自己大的,由于除了顶点以外,每个数的后面都有一个比自己大一的数,所以右侧比较好找。而对于左侧,我们结合上图去思考,不难发现最终形成的 序列就是若干个等腰直角三角形排在一起,那么每个数作为最大值的区间可以延展到的左端点一定是在 的位置。因此我们像之前那样用一个单调栈就行了。
但是对于每个数都用单调栈的话显然会寄。
我们可以找一下规律:

考虑对第 个子段的每个元素的答案进行统计,我们发现 这一段对应过去的线段是 ,这说明 的元素 可以向左延伸的最远点都是 ,即 。而 对应过去是 的一个子线段,这说明 的元素 向左延伸的最远点都是 。这启示我们将每一个子段中的元素分成若干个子部分进行处理,并且要保证每个部分的 对应的左侧端点是相同的。
于是我们用单调栈去储存 ,维护一个单调递减的子序列的下标。当我们要处理第 个子段时,我们就在栈中从后往前遍历,设当前遍历的元素为 ,上一个遍历的元素是 ,那么我们就将 的答案进行加和,下文令 ,,则:
$$\begin{aligned} \sum _{j=b_q+1}^{b_p}j(s_{i,j}-s_{p,b_p})&=\sum _{j=b_q+1}^{b_p}j(sum_{i-1}-sum_p+j)\\ &=\sum _{j=1}^{m}(b_q+j)(sum_{i-1}-sum_p+b_q+j)\\ &=mb_qt+\dfrac{m(b_q+t)(m+1)}{2}+\dfrac{m(m+1)(2m+1)}{6} \end{aligned} $$这样就可以 计算这一段的答案之和了。
根据单调栈的性质,可以推断 个子段分成的子部分的个数和是 级别的,可以跑过。
最后就是一些细节问题了,放代码:
#include<bits/stdc++.h> #define int long long using namespace std; const int MAXN=1e6+5; const int MOD=998244353; int n,a[MAXN]; stack<int> stk; int res; int L[MAXN],R[MAXN]; int sum[MAXN]; int qpow(int x,int y) { int res=1; while(y) { if(y&1) res=1ll*res*x%MOD; x=1ll*x*x%MOD; y>>=1; } return res; } int solve(int x,int y,int z){ return (1ll*x*y%MOD*z%MOD+1ll*(x+y)%MOD*(1ll*(z+1)*z/2%MOD)%MOD+1ll*z*(z+1)%MOD*(2*z+1)%MOD*qpow(6,MOD-2)%MOD)%MOD; } signed main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i],sum[i]=sum[i-1]+a[i],sum[i]%=MOD; a[n+1]=a[n]; for(int i=1;i<=n;i++) { while(!stk.empty()&&a[stk.top()]<a[i]) R[stk.top()]=i,stk.pop(); if(!stk.empty()) L[i]=stk.top(); stk.push(i); } while(!stk.empty()) R[stk.top()]=n+1,stk.pop(); for(int i=1;i<=n;i++) res+=1ll*a[i]*(sum[i]-sum[L[i]]+MOD)%MOD*(sum[R[i]-1]-sum[i]+1+(R[i]<=n)*a[i]+MOD)%MOD,res%=MOD; while(!stk.empty()) stk.pop(); stk.push(0),a[0]=1e9; for(int i=1;i<=n;i++) { int lst=0; while(!stk.empty()&&a[stk.top()]<=a[i]-1) res+=solve(sum[i-1]-sum[stk.top()]+lst,lst,a[stk.top()]-lst),lst=a[stk.top()],stk.pop(); if(lst!=a[i]-1) res+=solve(sum[i-1]-sum[stk.top()]+lst,lst,a[i]-lst-1),res%=MOD; while(!stk.empty()&&a[stk.top()]==a[i]) stk.pop(); stk.push(i); } cout<<res; return 0; }
- 1
信息
- ID
- 10051
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者