CF83A Magical Array 题解

Content

有一个长度为 \(n\) 的序列 \(a_1,a_2,a_3,...,a_n\)。定义一个“神奇数组”为在上面的序列中最大值和最小值相等的子序列。求出这个序列中“神奇数组”的个数。

数据范围:\(1\leqslant n\leqslant 10^5,0\leqslant|a_i|\leqslant 10^9\)

Solution

这个题目直接模拟肯定会爆炸,所以我们考虑一个更高效率的算法。

首先,我们明显知道,最小值与最大值都相等的序列就是所有元素都相等的序列。

我们先通过样例来找找规律:

  • 长度为 \(4\) 的序列 \(\{2,1,1,4\}\) 的答案是 \(5=1\times(1+2)\div2+2\times(2+3)\div2+1\times(1+2)\div2\)
  • 长度为 \(5\) 的序列 \(\{-2,-2,-2,0,1\}\) 的答案是 \(8=3\times(3+1)\div2+2\times1\times(1+2)\div2\)

是不是发现规律了?

我们可以归纳出来:如果有一个长度为 \(k\),且最小值与最大值都相等的序列,那么这里面的“神奇数组”有 \(\dfrac{k(k+1)}{2}\) 个。

那么,这道题目很明显就出来了。

注意这里数据范围大,要开 \(\texttt{long long}\)

Code

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;

int n, a[100007];
long long ans, cnt = 1;

int main() {
	scanf("%d%d", &n, &a[1]);
	for(int i = 2; i <= n; ++i) {
		scanf("%d", &a[i]);
		if(a[i] == a[i - 1])	cnt++;
		else {
//			printf("%d\n", cnt * (cnt + 1) / 2);
			ans += cnt * (cnt + 1) / 2;
			cnt = 1;
		}
	}
	ans += cnt * (cnt + 1) / 2;
	printf("%lld", ans);
}
posted @ 2021-12-21 20:55  Eason_AC  阅读(88)  评论(0)    收藏  举报