CF1151E 零件计数

1 CF1151E 零件计数

2 题目描述

时间限制 \(1s\) | 空间限制 \(256M\)

\(Kremland\) 的花园是 \(n\) 个节点的一棵树(没有环的无向连通图)。每个节点 \(i\) 都有自己的值 \(a_i\)。所有的节点都通过边串行连接起来。也就是说,对于所有的 \(1≤𝑖<𝑛\) 都有一个连接节点 \(i\)\(i+1\) 的边。定义函数 \(𝑓(𝑙,𝑟)\),有两个参数 \(l\)\(r\) 而且 \((𝑙≤𝑟)\)

  • 我们只保留节点值在 \(l\)\(r\) 之间的节点。
  • 函数的值是在新图里面连接部件的个数。

你的任务是计算下面的累加和:\(\sum_{l=1}^{n} \sum_{r=l}^{n}{f(l,r)}\)

数据范围:\(1≤𝑛≤10^5\)

3 题解

我们发现,由于整个图的结构是一条链,所以一个联通块就是一些连续的数。

此时我们假设某个联通块里有 \(k\) 个节点,那么这个联通块中就有 \(k-1\) 对节点相邻。根据这个规律,我们可以发现:对于一个 \(f(l, r)\),假设从 \(l\)\(r\) 的数共有 \(x\) 个,且有 \(y\) 对数相邻,那么 \(f(l, r)\) 就等于 \(x - y\)。根据加法交换律,最终的答案就是所有可能的 \(f(l, r)\) 中的总节点个数减去相邻的节点对数。而我们对这个式子进一步拆分,可以看成:对于每一个数,所有将其包括的区间 \([l, r]\) 所对应的 \(f(l, r)\) 都加一,而对于每一对相邻的数,把将这两个数都包括的区间 \([l,r]\) 所对应的 \(f(l, r)\) 都减一。那么我们只需要算出将每一个数包括的区间个数与将每一对相邻的数包括的区间个数即可。

显然,对于数 \(s\),我们要找的区间 \([l, r]\) 必定满足 \(l \le s\)\(s \le r\)。此时 \(l\) 的取值范围就是 \([1,s]\)\(r\) 的取值范围就是 \([s, n]\)。根据乘法原理,所有的情况数就是 \(l\) 可能的取值数乘上 \(r\) 可能的取值数,也就是 \(s * (n - s+1)\)。即第 \(i\) 个数 \(a_i\) 对总答案数的贡献为 \(a_i * (n - a_i + 1)\)。对于相邻的两个数 \(t_0\)\(t_1\) 也是类似。要找的区间 \([l, r]\) 必定满足 \(l \le min(t_0, t_1)\)\(max(t_0, t_1) \le r\)。因此情况数就是 \(min(t_0, t_1) * (n - max(t_0, t_1) + 1)\),而我们的答案就要减去这个值。

4 代码(空格警告):

#include <iostream>
using namespace std;
const int N = 1e5+10;
#define int long long
int n, ans;
int a[N];
signed main()
{
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i], ans += a[i] * (n - a[i] + 1);
    for (int i = 1; i < n; i++) ans -= min(a[i], a[i+1]) * (n - max(a[i], a[i+1]) + 1);
    cout << ans;
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-03-09 21:28  David24  阅读(61)  评论(0编辑  收藏  举报