题目链接:Codeforces 1151E

Kremland 的王国是有 $n$ 个节点的树,第 $i$ 个节点有权值 $a_i$,对于所有的 $1 \le i < n$ 都有一条连接节点 $i$ 和 $i + 1$ 的边。

对于整数 $l, r(l \le r)$,我们设函数 $f(l, r)$ 表示:

  • 我们将权值在区间 $[l, r]$ 内的点保留。
  • 函数的值为新图中连通块的数量。

你需要求出如下式子的值:

$$ \sum_{l = 1} ^ n \sum_{r = l} ^ n f(l, r) $$

数据范围:$1 \le n \le 10 ^ 5$,$1 \le a_i \le n$。


Solution

我们对每个权值 $a_i$ 考虑贡献。很显然答案就是所有的 $a_i$ 可以在多少个区间 $[l, r]$ 内成为某个连通块的左端点。

对于 $a_i$,如果它要成为某个连通块的左端点,那么必然和 $i - 1$ 这个点之间没有边。现在要求的就是:有多少个权值区间 $[l, r]$ 会删除 $i - 1$ 但会保留 $i$ 这个点。

对于 $a_i, a_{i - 1}$ 分类讨论。

  • $a_{i - 1} < a_i$ 时:左端点区间为 $(a_{i - 1}, a_i]$,右端点区间为 $[a_i, n]$,故可行的区间 $[l, r]$ 有 $(a_i - a_{i - 1}) \cdot (n - a_i + 1)$ 个。
  • $a_{i - 1} > a_i$ 时:左端点区间为 $[1, a_i]$,右端点区间为 $[a_i, a_{i - 1})$,故可行的区间 $[l, r]$ 有 $(a_{i - 1} - a_i) \cdot a_i$ 个。

时间复杂度:$\mathcal O(n)$。


Code

#include <cstdio>
#include <algorithm>

const int N = 1e5 + 5;

int n, a[N];

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    long long ans = 0;
    for (int i = 1; i <= n; i++) {
        if (a[i] > a[i - 1]) {
            ans += 1LL * (a[i] - a[i - 1]) * (n - a[i] + 1);
        }
        if (a[i] < a[i - 1]) {
            ans += 1LL * (a[i - 1] - a[i]) * a[i];
        }
    }
    printf("%lld\n", ans);
    return 0;
}
最后修改:2019 年 06 月 28 日
如果觉得我的文章对你有用,请随意赞赏