UVALive 4850 Installations
传送门:https://vjudge.net/problem/UVALive-4850
题目大意:有若干个任务,每个任务耗时si,期限为di,同一时间只能做一个任务。对于一个任务,惩罚值为max(0,完成时间-期限)。问怎么安排,使(最大惩罚值+次大惩罚值)最小。
题解:
首先如果需要最大惩罚值最小,就直接把结束时间sort一下,一次填入任务即可,对于截止时间相同的任务,随便怎么填都是一样的。然后我们就可以求出最小的最大惩罚值了。但是此题需要最大与次大的和最小,那么我们可以先求出最大的与次大的,然后p=max(pfirst,psecond),那么我们每一次从前面找出一个任务,塞到p这一个位置,前门的任务向前推,再统计一边最大与次大值,枚举需要O(n),统计答案O(n),所以O(n2)。
我们抽出一个任务之后,首先对于p后面的任务和抽出的i前面的任务没有任何影响,抽出之后最大值和次大值都会减小,塞入i到p之后,i的惩罚为最大值(或次大值)了(i的截止时间一定再原来的p任务之前,p任务是最大或次大,i抽到后面,自然会更大),对于当i在最大与次大之前,那么i是最大,如果最大在前面,次大在后面,而i有介于二者之间,那么i就是次大的了。
1 #include<queue> 2 #include<cstdio> 3 #include<vector> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 #define RG register 8 #define LL long long 9 #define fre(a) freopen(a".in","r",stdin);//freopen(a".out","w",stdout); 10 using namespace std; 11 const int MAXN=11000,INF=0x3f3f3f3f; 12 int Case,n,ans1,ans2,ans,p; 13 int id[MAXN]; 14 struct ed 15 { 16 int s,d,p; 17 }a[MAXN]; 18 bool comp(ed x,ed y) { return x.d<y.d; } 19 void cal(int &v1,int &v2,int &pos) 20 { 21 int now=0;v1=v2=0; 22 for(int i=1;i<=n;i++) 23 { 24 now+=a[id[i]].s; 25 if(now>a[id[i]].d) 26 { 27 if(now-a[id[i]].d>v1) 28 v2=v1,v1=now-a[id[i]].d,pos=i; 29 else if(now-a[id[i]].d>v2) 30 v2=now-a[id[i]].d,pos=i; 31 } 32 } 33 } 34 int main() 35 { 36 scanf("%d",&Case); 37 while(Case--) 38 { 39 scanf("%d",&n); 40 for(int i=1;i<=n;i++) 41 scanf("%d%d",&a[i].s,&a[i].d),id[i]=i; 42 sort(a+1,a+n+1,comp); 43 ans1=ans2=0;ans=INF; 44 cal(ans1,ans2,p); 45 ans=ans1+ans2; 46 for(int i=1,v1,v2,g;i<p;i++) 47 { 48 for(int j=i;j<p;j++)id[j]=id[j+1]; 49 id[p]=i; cal(v1,v2,g); 50 ans=min(ans,v1+v2); 51 for(int j=1;j<=n;j++)id[j]=j; 52 } 53 printf("%d\n",ans); 54 } 55 return 0; 56 }