Educational Codeforces Round 61 (Rated for Div. 2) D. Stressful Training(贪心+二分+优先队列)

题目链接:http://codeforces.com/contest/1132/problem/D

题目大意

每个同学电脑有初始电量和电量消耗速度,
这堂课有k分钟,其损耗过程有note描述。
现在有个输出x,每分钟可以指定一个电脑并充电x,
问要维护每位同学电脑电量始终不小于零,其最小的x是多少。

题目分析

这道题思路倒是蛮容易想的,就是细节比较多!
可以看出是二分,并且二分上界是12次方,题目凑好的,
不然过程中可能会有越界。
我们用优先队列维护过程中的电脑电量,
我们肯定优先选择支撑分钟最少的电脑,
如果电脑支撑分钟一样则无需细分,不难发现:
如果因为这次充电次数增加,那么下一次会轮到下一个最少的,
如果情况本身会超出界限,那么最终结果不会因为其顺序而影响,
关于这一点稍微模拟下不难发现。
那么对于每次取出来的节点,判定是否符合要求,如果符合则充电并再丢进去。
这里时间常数比较大,因为优先队列本身自带log,
下面是几个剪枝点:
上界可以预处理出来,这里我并没有这样做。。。
如果取出的最少次数都大于k那么一定可以成功(第二个if)
六十四位除法,关于次数的比较我们不要在优先队列的优先级比较里面写除法
而通过增加变量的方式来代替(重点:看来计组还是要好好学的。。。)
时间复杂度:O(nlog(1e12)*logn)

#include<bits/stdc++.h>
using namespace std;

#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long

#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=2e5+5;
const int ub=1e6;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:
每个同学电脑有初始电量和电量消耗速度,
这堂课有k分钟,其损耗过程有note描述。
现在有个输出x,每分钟可以指定一个电脑并充电x,
问要维护每位同学电脑电量始终不小于零,其最小的x是多少。

题目分析:
这道题思路倒是蛮容易想的,就是细节比较多!
可以看出是二分,并且二分上界是12次方,题目凑好的,
不然过程中可能会有越界。
我们用优先队列维护过程中的电脑电量,
我们肯定优先选择支撑分钟最少的电脑,
如果电脑支撑分钟一样则无需细分,不难发现:
如果因为这次充电次数增加,那么下一次会轮到下一个最少的,
如果情况本身会超出界限,那么最终结果不会因为其顺序而影响,
关于这一点稍微模拟下不难发现。
那么对于每次取出来的节点,判定是否符合要求,如果符合则充电并再丢进去。
这里时间常数比较大,因为优先队列本身自带log,
下面是几个剪枝点:
上界可以预处理出来,这里我并没有这样做。。。
如果取出的最少次数都大于k那么一定可以成功(第二个if)
六十四位除法,关于次数的比较我们不要在优先队列的优先级比较里面写除法
而通过增加变量的方式来代替(重点:看来计组还是要好好学的。。。)
时间复杂度:O(nlog(1e12)*logn)
*/
ll n,k;
ll a[maxn],b[maxn];
struct node{
    ll x,y,tim;
    bool operator<(const node& q) const {
        return tim>q.tim;///剪枝
    }
};
bool judge(ll x){
    priority_queue<node> pq;
    rep(i,1,n+1) pq.push(node{a[i],b[i],a[i]/b[i]});
    for(ll i=0;i<k;i++){
        node tp=pq.top();pq.pop();
        if(tp.x-i*tp.y<0) return false;
        if(tp.x/tp.y>k) return true;///剪枝
        tp.x+=x;pq.push(node{tp.x,tp.y,tp.x/tp.y});
    }
    return true;
}
int main(){
    scanf("%lld%lld",&n,&k);
    rep(i,1,n+1) scanf("%lld",&a[i]);
    rep(i,1,n+1) scanf("%lld",&b[i]);
    ll l=0,r=2e12;///这里还有一个加速点,可以预判定其上界
    while(l<r){
        ll mid=l+r>>1;
        if(judge(mid)) r=mid;
        else l=mid+1;
    }
    if(r==2e12) puts("-1");
    else printf("%lld\n",r);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37451344/article/details/88603851