观光公交
【题目分析】
一看题目的数据范围,就觉得是一道dp题,然后就在考虑状态如何转移,然后就……..放弃了,这TM根本就不是一道dp题,这一次使用加速器会对接下来的一段区间造成影响,但我怎么知道影响到哪里!
清空之前的思路,我们从原始的思路开始想,枚举。枚举这个加速器在哪一段使用,这样会对最终的答案造成什么影响,影响有多大。我们发现,车的出发时间与自身到达的时间、这个站点来的最晚的那个人的时间有关。如果给这一段无限加速,对答案的影响其实并不大,所以,贪心的思路就有了。
至于为什么是对的,其实已经很清楚了。对这个区间加速,他影响答案会因为这个站点来的最晚的那个人的时间所“打断”,贡献是有限的,用一句哲理性的话来总结:
“我的整个生命和全部精力,都已经献给世界上最壮丽的事业——为人类的解放而斗争。”
我们要用有限的加速器创造更大的影响。
既然这样,60分就到手了。
【60分代码】
#define M 1005
#define oo 1e16
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int n,m,k,p;
int D[M],S[10*M],T[10*M],tim[10*M];
ll ans=oo,an=oo;
vector<int>shang[M],xia[M];
int shangmx[M];
void Rd(int &res){
char c;res=0;
while(c=getchar(),!isdigit(c));
do{res=(res<<3)+(res<<1)+(c^48);}while(c=getchar(),isdigit(c));
}
void check(int w){
ll res=0;
int T=0,i,j;
for(i=1;i<=n;i++){
for(j=0;j<xia[i].size();j++){
int q=xia[i][j];
res+=T-tim[q];
}if(T<shangmx[i])T=shangmx[i];
T+=D[i];
}
if(res<an)an=res,p=w;
}
int main(){
int i,j;
Rd(n),Rd(m),Rd(k);
for(i=1;i<n;i++)Rd(D[i]);
for(i=1;i<=m;i++){
Rd(tim[i]),Rd(S[i]),Rd(T[i]);
shang[S[i]].push_back(i);
xia[T[i]].push_back(i);
shangmx[S[i]]=max(tim[i],shangmx[S[i]]);
}
check(0);
ans=an;
while(k--){
an=oo;
for(i=1;i<n;i++){
if(!D[i])continue;
D[i]--;
check(i);
D[i]++;
}
if(an>ans)break;
ans=an;
D[p]--;
}cout<<ans<<endl;
return 0;
}
上面的代码的复杂度是O(k*n^2),k是少不了了,就是查询太慢了。不过在赛场上写出来的话,其实已经很不错了,只要前面的水题不要爆,分数已经是很理想了。
至于100分到底怎么写,这是一个问题。
我们通过看上述暴力的代码,知道了如果在这个区间使用加速器,会影响到接下来的区间,而对之前的区间并没有影响。根据我们伟大的贪心,优化原本是m的询问吧。
【代码】
#define M 1005
#include<cstdio>
#include<iostream>
using namespace std;
int t[M*10],fr[M*10],to[M*10];
int d[M],ge[M],last[M],ar[M];
long long ans;
int n,m,k;
int main(){
int i,j;
scanf("%d %d %d",&n,&m,&k);
for(i=1;i<n;i++)scanf("%d",&d[i]);
for(i=1;i<=m;i++){
scanf("%d %d %d",&t[i],&fr[i],&to[i]);
last[fr[i]]=max(last[fr[i]],t[i]);
ge[to[i]]++;
}ar[1]=last[1];
while(k--){
for(i=2;i<=n;i++)ar[i]=max(ar[i-1],last[i-1])+d[i-1];
int pos=0,mx=0;
for(i=1;i<n;i++){
if(!d[i])continue;
int temp=0;
for(j=i+1;j<=n;j++){
temp+=ge[j];
if(ar[j]<=last[j])break;
}
if(temp>mx)mx=temp,pos=i;
}
if(!pos)break;
d[pos]--;
}
for(i=2;i<=n;i++)ar[i]=max(ar[i-1],last[i-1])+d[i-1];
for(i=1;i<=m;i++)ans+=ar[to[i]]-t[i];
cout<<ans<<endl;
return 0;
}