专栏文章

题解:P14567 【MX-S12-T2】区间

P14567题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min31x6d
此快照首次捕获于
2025/12/01 19:45
3 个月前
此快照最后确认于
2025/12/01 19:45
3 个月前
查看原文

题解:P14567 【MX-S12-T2】区间

闲话:

本蒟蒻初二,冲刺 NOIPNOIP 一等奖。
赛时 1010 分钟切了第一题,3030 分钟切了第二题,然后就啥而不会了,喜提 210210 分。

题意:

求一个代价最小的合法区间 [l,r][l, r]
合法区间的定义:任何一个出现在区间内的颜色都不能出现在区间外。

思路:

提供一个简单而又略带卡常的做法。
首先先打暴力,复杂度为 O(n3)O(n^3)
考虑在暴力的基础上进行优化:
我们发现随着区间右端点逐渐递增,代价也逐渐递增,所以可以直接剪枝,即对于每一个左端点找到合法的下标最小的右端点并统计答案。
随着右端点的递增,如果发现存在颜色 xx 和下标 i,ji, j 满足 ci=cj=xc_i = c_j = xi[l,r]i \in [l, r]j[1,l)j \in [1, l),那么无论右端点怎么向右移,一定不可能再合法了,直接剪枝。
献上我的优良代码:

代码:

CPP
#include<bits/stdc++.h>

using namespace std;
#define I return
#define love 0
#define coding

int n,c[1000050],v[1000050],f[1000050],pre[1000050],lst[1000050],mx;
long long ans = 1e18+7;

inline long long calc(int x,int y){
	long long res = 0;
	for(int i = x;i <= y;++i) res+=(1LL*v[i]*f[i-x+1]);
	return res;
}
inline int rd(){
	int x = 0,f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9'){
		x = x*10+ch-'0';
		ch = getchar();
	}
	return x*f;
}
inline void wt(long long x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9) wt(x/10);
    putchar(x%10+'0');
}

int main(){
//	freopen("T1.in","r",stdin);
	ios::sync_with_stdio(false);
	cin.tie(0);
	n = rd();
	for(int i = 1;i <= n;++i) c[i] = rd();
	for(int i = 1;i <= n;++i) v[i] = rd();
	for(int i = 1;i <= n;++i) f[i] = rd();
	for(int i = 1;i <= n;++i){
		lst[c[i]] = i;
		if(pre[c[i]]) continue;
		pre[c[i]] = i;
	}
	for(int i = 1;i <= n;++i){
		mx = 0;
		for(int j = i;j <= n;++j){
			mx = max(mx,lst[c[j]]);
			if(pre[c[j]] < i) j = n+1;
			else if(mx == j){
				ans = min(ans,calc(i,j));
				j = n+1;
			}
		}
	}
	wt(ans);
	I love coding;
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...