神题,莫名其妙WA了可以尝试多多取模(窝加一个%分数就涨10多分,醉了)
Soltuion Norma
题目大意:求
\[\sum_{i=1}^{n}\sum_{j=i}^{n}(j-i+1) \cdot min[j,i] \cdot max[j,i]\]
\(cdq\)分治
分析:
求树上所有点对我们有点分治,求所有子序列我们也可以考虑\(cdq\)分治
设当前统计\([l,r]\),中点\(mid\),我们要统计跨\(mid\)的子序列对答案的贡献
不难想到,我们用一个指针\(i \in[l,mid]\)逆序枚举,这样我们可以在\(O(n)\)的时间内统计出序列在\(mid\)左端部分的最小/大值
然后我们看\([i,mid]\)这段对右边的影响,我们设右端第一个小于\(val[i]\)的位置为\(p\),第一个大于\(val[i]\)的位置为\(q\),\([i,mid]\)这段最小/大值为\(mi/mx\)
分类讨论,不妨设\(p < q\),另一种情况同理
- \(1.\)右端点\(j \in (mid,p)\)
对答案的贡献
\(mi \cdot mx \cdot \sum_{j=mid+1}^{p-1}(j-i+1)\)
显然左边一个常数,右边等差数列求和(高斯笑而不语)
- \(2.\)右端点\(j \in [p,q)\)
对答案的贡献
\(mx \cdot \sum_{j=p}^{q-1}min[j] \cdot(j-i+1)\)
其中\(min[j]\)表示\([mid + 1,j]\)中最小值,\(max[j]\)同理
这玩意儿不好算拆开来
\(mx \cdot (\sum_{j=p}^{q-1}(min[j] \cdot j - min[j] \cdot i + min[j]))\)
我们维护一下\(min[j],min[j] \cdot j\)的前缀和即可
- \(3.\)右端点\(j\in[q,r]\)
对答案贡献
\(\sum_{j=q}^{r}min[j] \cdot max[j] \cdot (j - i + 1)\)
拆拆拆
\(\sum_{j=q}^{r}(min[j] \cdot max[j] \cdot j - min[j] \cdot max[j] \cdot i + min[j] \cdot max[j])\)
同理,维护\(min[j]\cdot max[j],min[j] \cdot max[j] \cdot j\)前缀和
\(p > q\)同理
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int maxn = 5e5 + 100,mod = 1e9;
typedef long long ll;
inline int read(){
int x = 0;char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))x = x * 10 + c - '0',c = getchar();
return x;
}
int n,val[maxn],mi,mx;
ll ans,smi[maxn],smii[maxn],smx[maxn],smxi[maxn],smix[maxn],smixi[maxn],p,q;
inline ll gauss(int l,int r){
return ll(l + r) * (r - l + 1) / 2 % mod;
}
inline ll getsum(ll *val,int l,int r){return (val[r] - val[l - 1]) % mod;}
inline void cdq(int l,int r){
if(l == r){(ans += (ll)val[l] * val[l]) %= mod;return;}
int mid = (l + r) >> 1;
cdq(l,mid),cdq(mid + 1,r);
smi[mid] = smii[mid] = smx[mid] = smxi[mid] = smix[mid] = smixi[mid] = 0;
mi = 0x7fffffff,mx = -0x7fffffff;
for(int i = mid + 1;i <= r;i++){
mi = min(mi,val[i]);
mx = max(mx,val[i]);
smi[i] = (smi[i - 1] + mi) % mod;
smii[i] = (smii[i - 1] + (ll)mi * i % mod) % mod;
smx[i] = (smx[i - 1] + mx) % mod;
smxi[i] = (smxi[i - 1] + (ll)mx * i % mod) % mod;
smix[i] = (smix[i - 1] + (ll)mi * mx % mod) % mod;
smixi[i] = (smixi[i - 1] + (ll)mi * mx % mod * i % mod) % mod;
}
mi = 0x7fffffff,mx = -0x7fffffff,p = q = mid + 1;
for(int i = mid;i >= l;i--){
mi = min(mi,val[i]);
mx = max(mx,val[i]);
while(p <= r && val[p] > mi)p++;
while(q <= r && val[q] < mx)q++;
if(p < q){
(ans += (ll)mx * mi % mod * gauss(mid - i + 2,p - i)) %= mod;
(ans += mx * (getsum(smii,p,q - 1) - (i * getsum(smi,p,q - 1) % mod) + getsum(smi,p,q - 1) + mod) % mod) %= mod;
(ans += (getsum(smixi,q,r) - (i * getsum(smix,q,r) % mod) + getsum(smix,q,r)) % mod + mod) %= mod;
}else{
(ans += (ll)mx * mi % mod * gauss(mid - i + 2,q - i)) %= mod;
(ans += mi * (getsum(smxi,q,p - 1) - (i * getsum(smx,q,p - 1) % mod) + getsum(smx,q,p - 1) + mod) % mod) %= mod;
(ans += (getsum(smixi,p,r) - (i * getsum(smix,p,r) % mod) + getsum(smix,p,r)) % mod + mod) %= mod;
}
}
}
int main(){
n = read();
for(int i = 1;i <= n;i++)val[i] = read();
cdq(1,n);
printf("%lld\n",ans);
return 0;
}