1 条题解
-
0
自动搬运
来自洛谷,原作者为

sysong
AFO搬运于
2025-08-24 22:23:46,当前版本为作者最后更新于2020-10-03 16:36:37,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题解 P6767 [BalticOI 2020/2012 Day0] Roses
用一种奇怪的姿势过了这题,还成了当时最优解,写一篇题解纪念一下。
题意
要买朵花,每朵元,每朵元,问最少要花多少元。
思路
注意:开 !
因为
首先挑便宜的买,然而——会多买,所以考虑用另外一种替换掉多余部分。
所以,我们可以写出代码片段:
(代替,代替)
ll n=rd(),a=rd(),b=rd(),c=rd(),d=rd(),ans=1e18; // a,b,c,d 严格按照题目要求, ans 记录最小值 ld x=b*1.0/a,y=d*1.0/c; // x,y 分别为 a,b 种花的单价 if(x>y)swap(a,c),swap(b,d); // 如果 a 的单价贵,那么交换,保证 a 的单价低 ll s=(n+a-1)/a; // 单价低的至少要买 s 束 // 这里 +a-1 相当于 ceil 函数 for(R ll i=s,k;i>=0;i--) // 总共有 s 种不过于浪费的买法 { k=i*b+max((ll)0,n-i*a+c-1)/c*d; // i*b 表示 a 种的总价格, // n-i*a 表示剩余需要花的朵数,同上求出总价格 if(k<ans)ans=k; // 打擂台选取最小值 } printf("%lld\n",ans);
然后,我们就这样提交,然而——取得了TLE的好成绩,还有一个点过不了。
怎么办呢?
我们发现,当我们把多买的部分替换掉之后,是会增加的(本来就挑便宜的买的嘛)
那是不是——
for(R ll i=s,k,f=1;i>=0&&f;i--) // 在这里设置一个 flag f ,如果价格开始增加, // 那么就不用再循环下去了 { k=i*b+max((ll)0,n-i*a+c-1)/c*d; if(k<ans)ans=k; else f=0; // 相当于 break; }
继续——WA
难道没有办法了吗?
还有什么问题?
我们再次发现(太难了):
我们拿掉的部分加上新买的部分,可能还是会多买。
看来也许我们是冤枉他了怎么解决呢?
我们看到上面那位dalao写了个(最小公倍数)来限制循环次数,实际上不需要。
因为!
我们最多只要循环就足以计算可能最优的情况了!
(求还要花时间,而且,的还可能比大)
那么就很简单了
#include <bits/stdc++.h> #define R register #define gc() getchar() #define ll long long #define ld long double using namespace std; inline ll rd(){ R ll x=0;R char c=gc(); while(c>'9'||c<'0')c=gc(); while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=gc(); return x; } // 快读加速 int main(){ ll n=rd(),a=rd(),b=rd(),c=rd(),d=rd(),ans=1e18; ld x=b*1.0/a,y=d*1.0/c; if(x>y)swap(a,c),swap(b,d); ll s=(n+a-1)/a; for(R ll i=s,k,f=100000;i>=0&&f;i--,f--) // 用 f 来限制循环次数 { k=i*b+max((ll)0,n-i*a+c-1)/c*d; if(k<ans)ans=k; } printf("%lld\n",ans); return 0; }
终于了!(另外组数据也已过)
码字不易,望通过!
by jsntsys
- 1
信息
- ID
- 5843
- 时间
- 500ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者