题解 | #小黑的区间#

小紫的总分

https://ac.nowcoder.com/acm/contest/84244/A

D-小黑的区间

现在定义dp[i]表示以i位置结尾的完美区间个数,不难发现,以i位置结尾的区间可以是i位置的一个数,也可以是i-1位置到i位置两个数,也可以时i-2到i位置三个数,直到这个区间内有两个相等的数,它们之间不存在与它们相等的值且它们之间的距离大于k。假设我们已经知道了第一个发生冲突的位置j,那么dp[i] = i - j

那么现在要求的就是第一个发生冲突的位置。当然可以一个一个枚举,然后直接超时...所以现在问题就是如何快速找出从后往前数第一个发生冲突的位置

假设在计算dp[i]时我们已经知道了和i - 1位置第一个发生冲突的位置j1,现在我们再计算和i位置的值第一个发生冲突的位置,设和i位置的值发生冲突的位置为j2,(注意j1是和i-1位置冲突的位置,即从j1 + 1到i - 1都不存在冲突的两个数,而j2是和i位置的值发生冲突的位置,即从后往前找的第一个与上一个和i位置相同的值距离大于k的位置),此时与i位置冲突的位置应该是max(j1, j2)。

我的方法是记录每个位置值与它相同的前一个位置,如果没有那么就默认为0,这样就可以轻松找出冲突的位置,如果不冲突,那么dp[i]就等于i - 0,i左边所有的位置都可以作为左区间。

代码如下:

#include<iostream>
#include<unordered_map>
#include<algorithm>
using namespace std;

int arr[100005];
int pre[100005];
long long dp[100005];
long long ans = 0;
unordered_map<int, int> m;
int n, k;

int findx(int ind) {
	int wind = pre[ind];
	while(wind > 0 && ind - wind <= k) {
		ind = wind;
		wind = pre[wind];
	}
	return wind;
}

int main() {
	scanf("%d%d", &n, &k);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &arr[i]);
		if(m.find(arr[i]) == m.end()) {
			pre[i] = 0;
		} else {
			pre[i] = m[arr[i]];
		}
		m[arr[i]] = i;
	}
	int wrongind = 0;
	for(int i = 1; i <= n; i++) {
		wrongind = max(wrongind, findx(i));
		dp[i] = i - wrongind;
		ans += dp[i];
	}
	printf("%lld", ans);
	return 0;
}
全部评论
感觉你的findx函数不对呀,如果距离小于等于k,你把ind赋值为了pre[ind],这样你的循环条件比的就是pre[ind]和pre[pre[ind]]的距离了,不应该是ind到它前面值相等的数的距离吗,比如样例1 4 3 2 1 4 1 2 k=3,最后一个1,它的pre是第二个1,然后按你的循环来运行的话,你比较的就是第一个1和第二个1的距离,返回第一个1的下标,不过刚好也是大于3的,按理说应该进入循环后再比较的应该是第一个1和最后一个1的距离,然后return第一个1的下标,下面是本蒟蒻改的findx int findx(int i){ if(pre[i]==0)return 0; if(i-pre[i]>k)return pre[i]; int d=pre[i]; while(d&&i-d<=k){ d=pre[d]; } return d; }
点赞 回复 分享
发布于 2024-06-03 23:26 湖北

相关推荐

评论
4
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务