CF1151E 题解
【题目大意】
给定一个有 n n n 个顶点的链式图,编号 1 ∼ n 1\sim n 1∼n,且 i i i 号节点的权值为 a i a_i ai. 对所有 1 ⩽ i < n 1\leqslant i<n 1⩽i<n,编号 i i i 和 i + 1 i+1 i+1 的点之间连有一条边.
定义函数 f ( l , r ) ( l ⩽ r ) f(l,r)(l\leqslant r) f(l,r)(l⩽r) 为删除权值范围不在 l l l 到 r r r 之间的点(某端为消失点的边也消失)后新图的连通块数量.
求 ∑ i = 1 n ∑ j = i n f ( i , j ) \sum_{i=1}^n\sum_{j=i}^nf(i,j) ∑i=1n∑j=inf(i,j) 的值。
【分析】
注意到此题中的图为一条链,并且求连通块数量,不难想到利用“连通块数量 = 点数 - 边数” ( 1 ) ^{(1)} (1)将原式转化为分别求点数和与边数和之差。(值得注意的是,这个公式只有在森林或树的情况下才成立)我们分别考虑每个点对答案的贡献。根据题意可得,权值为 a i a_i ai 的点只有 l ⩽ a i l\leqslant a_i l⩽ai 且 a i ⩽ r a_i\leqslant r ai⩽r 时才会做出贡献,而隐藏条件 1 ⩽ l , r ⩽ n 1\leqslant l,r\leqslant n 1⩽l,r⩽n 可知,该点会做出 a i × ( n − a i + 1 ) a_i\times(n-a_i+1) ai×(n−ai+1) 次贡献。因此,点数之和为 ∑ i = 1 n a i ( n − a i + 1 ) \sum_{i=1}^na_i(n-a_i+1) ∑i=1nai(n−ai+1)。边数之和也是如此,两端权值分别为 a i a_i ai 和 a i + 1 a_{i+1} ai+1 的边做出贡献时需要满足 l ⩽ a i ⩽ r l\leqslant a_i\leqslant r l⩽ai⩽r 且 l ⩽ a i + 1 ⩽ r l\leqslant a_{i+1}\leqslant r l⩽ai+1⩽r,也就是 l ⩽ min ( a i , a i + 1 ) l\leqslant\min(a_i,a_{i+1}) l⩽min(ai,ai+1) 以及 r ⩾ max ( a i , a i + 1 ) r\geqslant \max(a_i,a_{i+1}) r⩾max(ai,ai+1),所以该边会被计算 min ( a i , a i + 1 ) × ( n − max ( a i , a i + 1 ) + 1 ) \min(a_i,a_{i+1})\times(n-\max(a_i,a_{i+1})+1) min(ai,ai+1)×(n−max(ai,ai+1)+1) 次。所以这题就做完了。
【代码】
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int s = 0, w = 1;
char ch = getchar();
for(; ch < '0' || ch > '9'; w *= ch == '-' ? -1 : 1, ch = getchar());
for(; ch >= '0' && ch <= '9'; s = 10 * s + ch - '0', ch = getchar());
return s * w;
}
const int MAXN = 100005;
int n, a[MAXN];
signed main(){
n = read();
for(int i = 1; i <= n; i++){
a[i] = read();
}
int res = 0;
for(int i = 1; i <= n; i++){
res += a[i] * (n - a[i] + 1);
}
for(int i = 1; i < n; i++){
res -= min(a[i], a[i + 1]) * (n - max(a[i], a[i + 1]) + 1);
}
cout << res << endl;
return 0;
}