题目链接: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 }
完。