跳到主要内容
原文200 词数1 分钟

题解:P9360 [ICPC 2022 Xi'an R] Clone Ranran

概述

操作一花 a 分钟让人数翻倍,操作二花 b 分钟让每人各出一道题,需出满 c 道题,求最短总时间。先做若干次翻倍再统一出题最优,枚举翻倍次数 i(至多 30 次,因 2 的 30 次方已超过 10 的 9 次方),此时总时间为 a 乘 i 加 b 乘 c 除以 2 的 i 次方上取整,取所有 i 的最小值。时间复杂度 O(log c)。

解题思路​

显然,操作一在操作二之前进行更具性价比。

因此,最合理的策略是优先执行若干次操作一,然后再进行操作二。

可以枚举操作一的执行次数:

  • 如果执行 nn 次操作一,可以得到 2n2^n 个人,所需时间为 anan。
  • 这 2n2^n 个人出 cc 道问题,每道题 bb 分钟,所需时间为 b⌈c2n⌉b\left\lceil\frac{c}{2^n}\right\rceil。

最多会执行 3030 次操作一,因为 230>1092^{30}>10^9 人已经足够多。

通过枚举所有可能的执行次数,计算每种情况下所需的总时间并取最小值,即:

min⁡n=030(an+b⌈c2n⌉)\min_{n=0}^{30}\left(an+b\left\lceil\frac{c}{2^n}\right\rceil\right)

参考代码​

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

using ll=long long;
const ll inf=0x3f3f3f3f3f3f3f3f;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--)
{
ll a,b,c;
cin>>a>>b>>c;
ll ans=inf;
for(int i=0;i<=30;i++)
{
ans=min(ans,i*a+(c+(1ll<<i)-1)/(1ll<<i)*b);
}
cout<<ans<<'\n';
}
return 0;
}