2019年9月15日晚间测试-T1

T1

题目描述:

  一开始你有一个数S,你可以通过两种操作改变这个值:

  1.给这个数加a

  2.给这个数乘b  

  问最少多少步操作可以使S变成T。

输入格式:

  一行4个数,分别代表S,T,a,b。

数据范围:

  1<S<T<1018

  1<a<1018

  2<b<1018

这道题比较恶心了,看到1018的数据范围可能就会想到这是不是数学,然后搜刮脑子里那少的可怜的数学公式或定理(我就是这么做的,然后浪费了好长时间QAQ)

不过我在手模样例的时候有了这么一个发现:

好像所有的情况都能化简成最后的这个式子即:

 

哦!天哪,这个wa太不吉利了(疯狂暗示)(˘•ω•˘)

不过这样我们就可以贪心的解决这道题了

while(s*b<t) s*=b,k++; 找到一个最大的k,使得bkS<T,然后 (T - bkS) / a找出W。

这样数据就都全了,可是怎么求解最小步数呢?

乘K次b肯定跑不了了,接下来要加多少次a呢?

我们可以每次都 用W%b来获得最末尾项加a的次数,然后用 W / b来把倒数第二位的项变为最末尾的项,如下图:

 

什么!你问如果Ci >b 怎么办?你可以想一想,如果它大于b,那你把它放到前一项里不是会更优吗?所以贪心的假定每一个C都小于b得到的就是优的结果。

好,那咱们现在把题交上去。。。。。

 

噫~好!我WA了!φ(≧ω≦*)♪ 

现在咱们来考虑一下到底是哪出锅了。(*/ω\*)

还是比较明显的,问题就出在这里 (T - bkS) / a不一定是个整数,也就是说,你找的这个最大的K其实不对,它没办法构成T。

不过好在解决办法也很简单——把每个K都找一遍不就行了,就是b是最小的2,那K等于100时它也有1267650600228229401496703205376,这个数远超最大数据1018

好!咱们再交一遍。。。。。。。

 

噫~好!我又WA了( ゚∀゚)    ,究其原因无非就是1018太大了,很容易爆long long,这时候判断K就不能用 s*b<t 了,而是要改用 while( s<t / b)(我觉得其实应该加上等于号的,但是不加也过了)

这次再交就没有问题了。( • ̀ω•́ )✧

 

最后附上代码和注释:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 long long s,t,a,b;
 4 long long ans = 1e18+7;//先赋一个大值 方便取min 
 5 int main()
 6 {
 7     cin>>s>>t>>a>>b;//读入数据 
 8     
 9     if( (t-s)%a==0 ) //就是不乘b,纯用a加 
10         ans = (t-s)/a;//如果能加出来就记录一下 
11     
12     long long k=0;//k就是指数 
13     while( s<t/b )//防止爆longlong的优化 
14     {
15         k++;//寻找每个k 
16         s*=b;//寻找每个k下的b(k)s 
17         if((t-s)%a!=0) continue;//没办法用a凑出t,那这个k肯定就不对了 
18         
19         long long now = k;//方便处理 
20         long long w = (t-s)/a;//找到 W 
21         
22         for(int i = 1; i<=k;i++)//循环多项式的每一项,找出常数C 
23         {
24             now += w%b;//加上这个常数C 
25             w/=b;//把倒数第二位的项变成最后一项 
26         }
27         ans = min(ans,now+w);//在每种情况的k下寻找最小的步数
28         //now+w是因为最后除完b会可能会剩下最高次项的常数 ,如果不剩下加个0也无所谓 
29     }
30     cout<<ans;//输出结果 
31 }

( • ̀ω•́ )✧感谢大佬Accoty_AM的帮助

(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤为美好的代码献上祝福

(o°ω°o)CSP(NOOP)RP++

 

posted @ 2019-09-16 16:54  Cainai-Liberty-Bird  阅读(161)  评论(0编辑  收藏  举报