题目
Luogu
1
≤
n
≤
1
,
000
,
1
≤
m
≤
10
,
000
,
0
≤
k
≤
100
,
000
,
0
≤
D
i
≤
1000
,
0
≤
T
i
≤
100
,
000
1≤n≤1,000,1≤m≤10,000,0≤k≤100,000,0≤D_i≤1000,0≤T_i≤100,000
1≤n≤1,000,1≤m≤10,000,0≤k≤100,000,0≤Di≤1000,0≤Ti≤100,000
思路
首先思考,问什么可以贪心?
据说当初考试时,很多人想的
D
p
Dp
Dp 然后就挂了
这也是出题人和考生玩心理战术
为了更好说明为什么可以贪心,我们记
f
i
f_i
fi 为不使用氮气加速到达
i
i
i 点时间,
c
n
t
i
cnt_i
cnti 为
i
i
i 点下车人数,
L
a
s
t
i
Last_i
Lasti在
i
i
i 点最晚出发时间
则
f
i
=
m
a
x
{
f
i
−
1
,
L
s
t
i
−
1
}
+
d
i
−
1
f_i=max\{f_{i-1},Lst_{i-1}\}+d_{i-1}
fi=max{fi−1,Lsti−1}+di−1
对发现我们只对
f
i
f_i
fi,
L
a
s
t
i
Last_i
Lasti 的大小关系会影响我们决策
也就是人等车和车等人两种
我们可以进行分类讨论
1.
f
i
>
L
a
s
t
i
f_i>Last_i
fi>Lasti(人等车)
由于它加速后也会影响到后一段,所以可以暴力找出在它后面连续的一段
f
j
>
L
a
s
t
j
f_j>Last_j
fj>Lastj
在这些位置下车的人都会提前
1
1
1 单位时间下车
2.
f
i
<
=
L
a
s
t
i
f_i<=Last_i
fi<=Lasti(车等人)
此时并不会对
i
i
i 后面的产生影响,只会影响这
c
n
t
i
cnt_i
cnti 个人
综上我们每次只需要这样一段就行了:
影响的人数是这一段下车人数之和
问题来了,为什么可以贪心?
口胡一下(因为贪心本身就不好说)
因为每一段有
D
i
D_i
Di 的限制
假设现在你就取包含这一段最大的区间
D
i
D_i
Di 又恰好是最小的
你早取晚取都会把
D
i
D_i
Di 取完,然后就裂成了两段
假设不取
D
i
D_i
Di 没有取
D
i
D_i
Di 优
每次取最大的影响人数
觉得应该可以从
D
p
Dp
Dp 决策最优来讲,但是懒,不会
代码
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#include<ctime>
#include<bitset>
#include<cmath>
#include<cstdio>
#include<climits>
#include<cstdlib>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
int read(){
bool f=0;int x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return !f?x:-x;
}
#define MAXN 100000
#define INF 0x3f3f3f3f
int d[MAXN+5],Last[MAXN+5],cnt[MAXN+5],f[MAXN+5];
int Max(int a,int b){return a>b?a:b;}
int T[MAXN+5],A[MAXN+5],B[MAXN+5];
int main(){//f[i]:到达 i 实际时间
int n=read(),m=read(),k=read();
for(int i=1;i<n;i++)
d[i]=read();
for(int i=1;i<=m;i++){
T[i]=read(),A[i]=read(),B[i]=read();
Last[A[i]]=Max(Last[A[i]],T[i]);
cnt[B[i]]++;
}
f[1]=0;
for(int i=2;i<=n;i++)
f[i]=Max(f[i-1],Last[i-1])+d[i-1];
while(k--){
int Maxnum=0,L=0,R=0;
for(int i=2;i<=n;i++){
if(d[i-1]==0) continue;
int tmp=0,p1=i,p2=n;
for(int j=i;j<=n;j++){
tmp+=cnt[j];
if(f[j]<=Last[j]){
p2=j;
break;
}
}
if(tmp>Maxnum)
Maxnum=tmp,L=p1,R=p2;
}
if(!Maxnum) break;
d[L-1]--;
for(int i=L;i<=R;i++)
f[i]--;
}
int ans=0;
for(int i=1;i<=m;i++)
ans+=f[B[i]]-T[i];
printf("%d\n",ans);
return 0;
}
思考
多积累对贪心题的认知