[NOIP2011]观光公交 题解
题目大意:
就省了吧
思路:
应该算是贪心。
不难发现,加速只对所有在使用加速器之后连续的一段下车时不用等人的站点下车的人有用。这非常重要。
先算出不加速时的和,并预处理出每个站点最迟到的人的时间、每个站下车的人数。然后一个一个放加速器,加速器放在惠及最多的人的一段,同时维护到每个站点的时间(判断用不用等人)。
于是就有了一种比较暴力的算法:每次n2暴力求解每次加速后停下来的站点,再修改答案、维护数组。
但是这似乎会TLE(虽然官方数据貌似AC了),于是就有了优化。你可以逆推求解停下来的站点,再用前缀和O(n)求解人数。
代码:
暴力:
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 const int M=100005,N=1005; 5 int n,m,k,i,j,mx,ans,t[M],off[M],last[M],come[M],down[M],dist[N]; 6 7 int read() 8 { 9 int x=0; 10 char ch=getchar(); 11 while (ch<'0' || ch>'9') ch=getchar(); 12 while (ch>='0' && ch<='9') x=(x<<1)+(x<<3)+ch-48,ch=getchar(); 13 return x; 14 } 15 16 int main() 17 { 18 n=read(),m=read(),k=read(); 19 for (i=1;i<n;i++) dist[i]=read(); 20 for (i=1;i<=m;i++) t[i]=read(),last[j=read()]=max(last[j],t[i]),off[down[i]=read()]++; 21 for (i=1;i<n;i++) come[i+1]=max(come[i],last[i])+dist[i]; 22 for (i=1;i<=m;i++) ans+=come[down[i]]-t[i]; 23 while (k--) 24 { 25 for (i=1;i<=n;i++) t[i]=0; 26 for (i=1;i<n;i++) 27 if (dist[i]) 28 for (j=i+1;j<=n;j++) 29 { 30 t[i]+=off[j]; 31 if (come[j]<=last[j]) break; 32 } 33 mx=0; 34 for (i=1;i<n;i++) 35 if (t[i]>mx) mx=t[i],j=i; 36 dist[j]--,ans-=t[j],come[++j]--; 37 for (;j<n;j++) come[j+1]=max(come[j],last[j])+dist[j]; 38 } 39 printf("%d\n",ans); 40 return 0; 41 }
优化:
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 const int M=100005,N=1005; 5 int n,m,i,j,k,mx,ans,t[M],far[N],sum[N],off[M],last[M],come[M],dist[N]; 6 7 int read() 8 { 9 int x=0; char ch=getchar(); 10 while (ch<'0' || ch>'9') ch=getchar(); 11 while (ch>='0' && ch<='9') x=(x<<1)+(x<<3)+ch-48,ch=getchar(); 12 return x; 13 } 14 15 int main() 16 { 17 n=read(),m=read(),k=read(); 18 for (i=1;i<n;i++) dist[i]=read(); 19 for (i=1;i<=m;i++) t[i]=read(),last[j=read()]=max(last[j],t[i]),sum[off[i]=read()]++; 20 for (i=1;i<n;i++) come[i+1]=max(come[i],last[i])+dist[i]; 21 for (i=1;i<=m;i++) ans=ans+come[off[i]]-t[i]; 22 for (i=1;i<=n;i++) sum[i]=sum[i]+sum[i-1]; 23 while (k--) 24 { 25 far[n-1]=n,mx=0; 26 for (i=n-2;i;i--) 27 if (come[i+1]>last[i+1]) far[i]=far[i+1]; else far[i]=i+1; 28 for (i=1;i<n;i++) 29 if (sum[far[i]]-sum[i]>mx && dist[i]) mx=sum[far[i]]-sum[i],j=i; 30 if (!mx) break; --dist[j],ans=ans-mx; 31 for (come[1]=0,i=1;i<n;i++) come[i+1]=max(come[i],last[i])+dist[i]; 32 } 33 printf("%d\n",ans); 34 return 0; 35 }
我一直在繁华的苍凉中徘徊着,用一颗OI的心寻找着生命和宇宙的美妙与玄奥。