P11432 [COCI 20242025 #2] 流明 Blistavost
P11432 [COCI 2024/2025 #2] 流明 / Blistavost
题目背景
译自 COCI 2024/2025 #2 T4。\(\texttt{4s,1G}\)。满分为 \(120\)。
题目描述
数轴的正半轴的整数点上布满了璀璨的水晶灯。起初,它们都是点亮的。
初始时,时刻为 \(0\),守卫在原点处。每单位时间,她可以选择向左或者向右移动一单位长度,也可以待在原地。
当守卫在一盏水晶灯所在的位置时,可以选择熄灭这盏水晶灯。熄灭不消耗时间。
有 \(n\) 个要求,每个要求形如三元组 \((l_i,r_i,t_i)\),表示:村民需要熄灭区间 \([l_i,r_i]\) 内的水晶灯,而且必须在时刻\({}\ge t_i\) 时才能熄灭这个区间内的水晶灯(也就是说,时刻 \(\lt t_i\) 时不能熄灭这个区间内任意一盏水晶灯)。
请你计算守卫至少需要多少单位时间才能满足村民的全部要求。
输入格式
第一行,一个正整数 \(n\)。
接下来 \(n\) 行,每行三个正整数 \(l_i,r_i,t_i\)。
输出格式
输出一行一个正整数,表示答案。
输入输出样例 #1
输入 #1
3
1 1 1
3 3 5
5 5 3
输出 #1
7
输入输出样例 #2
输入 #2
3
1 2 1
1 1 5
1 3 4
输出 #2
6
输入输出样例 #3
输入 #3
3
6 6 6
8 8 7
9 9 9
输出 #3
9
说明/提示
样例解释
样例 \(2\) 解释:
时刻 \(3\) 时走到 \(x=3\) 处,停留一单位时间。
时刻 \(4\) 时,熄灭 \(x=3\) 的水晶灯。
时刻 \(5\) 时,走到 \(x=2\) 并熄灭上面的水晶灯。
时刻 \(6\) 时,走到 \(x=1\) 并熄灭上面的水晶灯。
耗时 \(6\) 单位时间。
提示
对于 \(100\%\) 的数据,保证:
- \(1\le n\le 5\, 000\);
- \(1\le l_i\le r_i\le 10^{18}\);
- \(1\le t_i\le 10^{18}\)。
| 子任务编号 | \(n\le\) | 特殊性质 | 得分 |
|---|---|---|---|
| $ 1 $ | \(18\) | A | $ 20 $ |
| $ 2 $ | \(5\, 000\) | B | $ 25 $ |
| $ 3 $ | \(5\, 000\) | A | $ 55 $ |
| $ 4 $ | \(5\, 000\) | $ 20 $ |
- 特殊性质 A:\(l_i=r_i\)。
- 特殊性质 B:\(l_i=1\)。
首先要挖掘性质,模拟一下关灯的过程可以发现关一个区间中的灯时,首尾的灯一定是要被关掉的,也就是说当首尾的灯被关掉之后,区间中的所有灯都可以被关掉。那么就可以把区间中的无数盏灯关闭的问题转化成关闭区间首尾的灯的问题。
那么可以将这些首尾灯单独拎出来,按照坐标大小排序。
然后可以想到,如果说\([l,r]\)中的\(l,r\)都没有被关,(\(l,r\)是灯在坐标数组中的下标),是需要把\([l,r]\)中所有的点都再跑一遍,这样才能关掉\(l,r\)两盏灯的,那么跑这一趟其实完全可以等价于只关\(l,r\),保持剩下的所有灯全部亮着,也就是\((l,r)\)为一段亮着的灯的连续区间,由此可以想出状态的定义:
设$ f_i,_j,_0\(表示\)(i,j]\(中全为亮灯且剩余灯全部被关闭的最小时间,\)f_i,_j,_1\(表示\)[i,j)$中全为亮灯且剩余灯全部被关闭的最小时间
则有
然后空间就爆炸了
若固定\(i\)时,\(j\)和\(len\)成正比,那么把\(j\)全部换成\(len\),然后可以发现\(f_i,_{len},_{0/1}\)仅和\(f_i,_{len+1},_{0/1}\)有关,再滚动一下就可以了
code:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e3+100;
struct light{
int pos,t,id;
friend bool operator<(light a,light b){
return a.pos<b.pos;
}
}a[N];
int ans=4e18,tot,f[N][N][2],n;
inline int dis(int x,int y){
return abs(a[x].pos-a[y].pos);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
int l,r,t;
cin>>l>>r>>t;
a[++tot]=light{l,t,tot};
a[++tot]=light{r,t,tot};
}
memset(f,0x6f,sizeof(f));
sort(a+1,a+1+tot);
f[1][tot][1]=max(a[tot].t,a[tot].pos);//[1,n)
f[1][tot][0]=max(a[1].t,a[1].pos);
for(int len=tot-1;len>=1;len--){
for(int i=1;i+len-1<=tot;i++){
int j=i+len-1;
if(i-1){
f[i][len][0]=min(f[i][len][0],max(f[i-1][len+1][0]+dis(i-1,i),a[i].t));
f[i][len][1]=min(f[i][len][1],max(f[i-1][len+1][0]+dis(i-1,j),a[j].t));
}
if(j+1<=tot){
f[i][len][0]=min(f[i][len][0],max(f[i][len+1][1]+dis(i,j+1),a[i].t));
f[i][len][1]=min(f[i][len][1],max(f[i][len+1][1]+dis(j,j+1),a[j].t));
}
if(len==1){
ans=min(ans,f[i][len][0]);
ans=min(ans,f[i][len][1]);
}
}
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号