D.小黑的区间

这题官方是用双指针做的,也是这题的一个很标准的做法,但比赛时笔者想到了用dp做的方法,觉得很不错,所以分享一波。

首先我们知道,对于一个区间[1,2,3]来说,如果想求其中有几个完美区间,显然是[1],[2],[3],[1,2],[2,3],[1,2,3]共六个,那么如果再加入一个4呢?答案是会多出[1,2,3,4],[2,3,4],[3,4],[4],共四个,加起来十个。那对于区间[1,2]呢?显然是[1],[2],[1,2]共三个。

如果观察能力强的同学可能会发现,对于一个区间a来说,每增加一个数,如果该区间仍是完美区间,那么完美区间的总个数=原来完美区间的个数+区间长度,即有dp[i]=dp[i-1]+len;

显然,加入的数如果和上一个相同的数距离大于k,就不是完美区间,此时只要用一个桶b来装各个数的最新位置,然后利用桶把区间长度减小即可。 接下来上代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
using pii = pair<int, int>;
using i64 = int64_t;
const int N = 1e5 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const double pi = 3.1415926535;


ll dp[N], b[N];  //记得开ll,不然会WA

void solve() {
	ll n, k;
	cin >> n >> k;
	ll len = 0;
	for (ll i = 1; i <= n; i++) {
		ll x;
		cin >> x;
		if (!b[x] || i - b[x] <= k || i - 1 - len > b[x]) {  //这里第三个条件是判断当
			len++;                                           //前的区间是否已经减去上
			b[x] = i;                                        //一个x,这样就不用改区间
			dp[i] = dp[i - 1] + len;                         
		} else {
			len = len + 1 - (b[x] - (i - 1 - len));         //修改区间大小
			b[x] = i;
			dp[i] = dp[i - 1] + len;
		}
	}
	cout << dp[n];
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int _ = 1;
	//cin >> _;
	while (_--)
		solve();

	return 0;
}

好了,这篇题解就到这里。我知道可能修改区间那里有点抽象,但本蒟蒻也想不到更合适的说法qwq,这是在下第一篇题解,希望各位观看愉快,如有问题欢迎讨论~