分析
看到这种满足要求的最小值
第一个想法就一定是二分答案
我们只需要明确一点
即:一定会优先给最快要没电的人充
所以很自然就会想到每个事件贪心维护最快要没电的人
使用priority_queue
(大佬们也可以手写堆。。。)
时间复杂度:
温馨提示
- 如果队列里边没有元素了,那么就返回
true
,无需多留 - 当前点会在限定时间内没电,那么才会进队
- 尽量不要使用过多的除法运算(因为我就是被这个东西卡了10+次提交)
- 由于这道题答案有点大,所以二分的有边界需要设到
2e12
cai'ke
代码
//CF1132D #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <queue> #include <cmath> #define LL long long #define Cl(X,Y) memset((X),(Y),sizeof(X)) #define FOR(i,A,B) for(LL i=A;i<=B;i++) #define BOR(i,A,B) for(LL i=A;i>=B;i--) #define Lowbit(X) (X & (-X)) #define Skip cout<<endl; #define INF 0x3f3f3f3f3f3f3f3f #define Rson (X<<1|1) #define Lson (X<<1) using namespace std; const int MaxN=2e5+10; LL Total,Time; struct Node { LL Sta,Use,Remain; friend bool operator < (Node A,Node B) { return A.Remain>B.Remain; } }Num[MaxN]; inline void File() { freopen(".in","r",stdin); freopen(".out","w",stdout); } inline bool Check(LL New) { priority_queue<Node>Mine; FOR(i,1,Total) if(Num[i].Sta/Num[i].Use<Time) Mine.push(Num[i]); int Cnt=0; if(Mine.empty()) return true; FOR(i,1,Time) { Node Temp=Mine.top(); Mine.pop(); if(Temp.Remain<Cnt) { return false; } Temp.Sta+=(New); Temp.Remain=Temp.Sta/Temp.Use; if(Temp.Remain<Time) Mine.push(Temp); if(Mine.empty()) return true; Cnt++; } return true; } inline LL Read() { LL Temp=0,Fac=1; char Ch=getchar(); while(Ch>'9' || Ch<'0') { if(Ch=='-') Fac=-1; Ch=getchar(); } while(Ch>='0' && Ch<='9') { Temp=(Temp<<1)+(Temp<<3)+(Ch ^ 48); Ch=getchar(); } return Fac*Temp; } signed main() { // File(); ios::sync_with_stdio(false); Total=Read(); Time=Read(); FOR(i,1,Total) { Num[i].Sta=Read(); } FOR(i,1,Total) { Num[i].Use=Read(); Num[i].Remain=Num[i].Sta/Num[i].Use; } LL L=0,R=2000000000000,Ans=-1; while(L<=R) { LL Mid=(L+R)>>1; if(Check(Mid)) R=Mid-1,Ans=Mid; else L=Mid+1; } printf("%lld\n",Ans); // fclose(stdin); // fclose(stdout); // system("pause"); return 0; }