#include<stdio.h> #include<string.h> #include<ctype.h> #include<math.h> #include<iostream> #include<string> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);} #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;} template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;} const int N=105,M=0,Z=1e9+7,ms63=1061109567; int casenum,casei; int n,m; pair<int,int>a[N]; pair<int,int>b[N<<1]; int v[N]; struct node { int o,ed; node(){} node(int o_,int ed_){o=o_;ed=ed_;} bool operator < (const node& b)const { return ed>b.ed; } }; priority_queue<node>q; bool ok(int tim) { for(int i=1;i<=n;i++)v[i]=tim; while(!q.empty())q.pop(); for(int i=1;i<=m;i++) { int t=b[i].first-b[i-1].first; while(t&&!q.empty()) { int o=q.top().o; int ed=q.top().ed; q.pop(); int need=min(v[o],t); v[o]-=need; t-=need; if(v[o])q.push(node(o,ed)); } int o=b[i].second; if(o<0)q.push(node(-o,a[-o].second));//新的任务加入 else if(v[o]>0)return 0;//时间到了却还没有做完 } return 1; } int main() { while(~scanf("%d",&n)) { m=0; for(int i=1;i<=n;i++) { scanf("%d%d",&a[i].first,&a[i].second); b[++m]=MP(a[i].first,-i); b[++m]=MP(a[i].second,i); } sort(b+1,b+m+1); int l=0; int r=10000/n; while(l<r) { int mid=(l+r+1)>>1; if(ok(mid))l=mid; else r=mid-1; } printf("%d\n",l*n); } return 0; } /* 【trick&&吐槽】 比赛的时候因为n很小,我们甚至可以采取O(log(10000)*n*10000)的复杂度做。 然而当然时候可以用更小复杂度的做法啦啦啦~~ 【题意】 有n([1,100])种活动,每个活动有一个开始时间st和结束时间ed(0<=st<=ed<=10000)。 我们想要从事每种活动以相同的时间,使得最终参与活动的总时间尽可能多。 【类型】 贪心+ STL-优先队列 or 暴力 【分析】 我们发现,总的从事活动的上界也不过才只有10000,于是答案不过超过10000,且一定是n的倍数。 于是—— 1,枚举从事每个活动的时间w(这个可以二分) 2,然后从前面的时间点开始往后贪。 对于一个时间点,我们从事什么活动呢? 因为对于每个活动,都要强行参与w的时间。 于是,如果有多个排在了一起,我们肯定也选择结束时间早的。 具体实现,可以是二分+10000vector的暴力选择,也可以是二分+双关键字排序priority_queue做。 priority_queue: 1,读入原始的pair a[],并且把每个pair拆成入点和出点,放到b[]中。 入点和出点对应着这个点的编号,和这个活动开始与结束的时刻。 2,把b[]做排序,也就是按照时刻排序,然后对b[]做顺序扫描。 在每个时间点之前,都有一个空余时间段。 我们还有任务没有完成(取出结束时间最早的),并且还有空余时间,那么我们就去做这个任务。 如果没做完,就把它再加回优先队列中。 然后开始处理这个时间点的事情了。 first,如果有新的任务出现,我们把它加进优先队列中 second,如果当前队列首的任务无法完成,就return 0 【时间复杂度&&优化】 O(nlogn) */