洛谷p1582倒水(思维好题,数学,2进制问题,代码实现)

题目链接:https://www.luogu.org/problemnew/show/P1582

题目猛一看挺难想,但想通了加的原理和合并的原理后就好说了。

肯定和2进制是紧密相连的,每个瓶子的水升数一定是2的倍数(因为每次合的都是一样的且都是2的倍数)

看透了这题后本质就是:将一个整数不断分解成2进制的表达形式存起来,再从后往前合并(每次ans加上前后两数之差就可以相等合并)<m时退出即可!

另外一个技巧是:算2的次幂不用每次都算,完全可以打表(很方便还省下不少时间)

 1 #include <iostream>
 2 #include <algorithm>
 3 typedef long long ll;
 4 using namespace std;
 5 ll b[70];
 6 ll t[70];
 7 ll n,m;
 8 
 9 void bit()
10 {
11     b[0]=1;
12     for(int i=1;i<=62;i++)
13     {
14         b[i]=b[i-1]*2;
15     }
16 }
17 
18 void sol()
19 {
20     ll x=n;
21     int k=0,p=0;
22     while(x)
23     {
24         for(int i=0;i<=70;i++)
25         {
26             if(b[i]>x)
27             {
28                 x-=b[i-1];
29                 //cout<<b[i-1]<<' ';//观察分解数,挺有用.
30                 t[++p]=b[i-1];
31                 k++;
32                 break;
33             }
34         }
35     }
36     //cout<<endl;
37     
38     if(k<=m)
39     {
40         cout<<"0"<<endl;
41         return;
42     }
43     
44     ll ans=0;
45     for(int i=p;i>=1;)
46     {
47         ans+=t[i-1]-t[i];
48         i--;
49         t[i]=t[i]*2;
50         
51         k--;
52         if(k<=m) break;
53     }
54     cout<<ans<<endl;
55 }
56 
57 int main()
58 {
59     bit();
60     
61     cin>>n>>m;
62     
63     sol();
64     
65     return 0;
66 }

完。

原文地址:https://www.cnblogs.com/redblackk/p/9940582.html