Windows 10
Total Submission(s): 957 Accepted Submission(s): 306
Problem Description
Long long ago, there was an old monk living on the top of a mountain. Recently, our old monk found the operating system of his computer was updating to windows 10 automatically and he even can’t just stop it !!
With a peaceful heart, the old monk gradually accepted this reality because his favorite comic LoveLive doesn’t depend on the OS. Today, like the past day, he opens bilibili and wants to watch it again. But he observes that the voice of his computer can be represented as dB and always be integer.
Because he is old, he always needs 1 second to press a button. He found that if he wants to take up the voice, he only can add 1 dB in each second by pressing the up button. But when he wants to take down the voice, he can press the down button, and if the last second he presses the down button and the voice decrease x dB, then in this second, it will decrease 2 * x dB. But if the last second he chooses to have a rest or press the up button, in this second he can only decrease the voice by 1 dB.
Now, he wonders the minimal seconds he should take to adjust the voice from p dB to q dB. Please be careful, because of some strange reasons, the voice of his computer can larger than any dB but can’t be less than 0 dB.
Input
First line contains a number
T
(
Next T line,each line contains two numbers
p
and
Output
The minimal seconds he should take
Sample Input
2
1 5
7 3
Sample Output
4
4
Author
UESTC
Source
2016 Multi-University Training Contest 6
题目大意:
电视机当前音量为p,想要调到q
有三中操作:
1.
加音量:一次只能+1
2.
减音量:严格二倍的减,如
−1−2−4−8
3.
停顿:占用一次操作,停顿后下一次减音量会重新从
−1
开始。
减音量与加音量之间的转换不需要停顿。
问从音量p变为q需要的最少操作次数。
立即可以想到,如果 p<=q ,答案即为 q−p
当p > q时。
w = p-q为需要减去的音量。
首先考虑纯减不加
那么会变成
1248−124−12
这种操作方式(
−
为停顿。)。
把每两次停顿间的操作当做一个块。
然后考虑添加加音量操作。从最低块开始。
以上为例,最低块+5后可以与它的上块合并。很容易证明,如果不合并,无论加多少音量都不如原状态更优。
这样可以把每个块表示为
同时处理一个数组
toti
表示第i个块减去的音量。
这样当
i
块与
然后再考虑加音量步骤的位置和停顿位置。
在处理出块的时候可以一并处理出来停顿的次数。
这样当压缩块的时候,可以优先把加音量操作塞到停顿处,也就是尽量减少操作。
然后xjb搞一下就出来结果了。
有个坑就是音量不能减为负,也就是说可能压缩块时一些加操作是没用的。因为减操作其实并没有减够,减为0就会cut,但是压缩的时候那部分溢出的减操作也会被无形的用加操作抵消。也就是出现了多余的加操作。
处理方法:暴力减到 <= q,然后加到p,会得到一个操作数。与压块的贪心操作数取最小即可
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <algorithm>
#include <cmath>
#include <ctime>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)
using namespace std;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
int a[66],b[66],c[66];
int tp;
int main()
{
int t,n,m;
//fread("");
//fwrite("");
int p,q;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&p,&q);
int ans;
if(q >= p) printf("%d\n",q-p);
else
{
tp = 0;
int tmp,k = 0;
int x = 1;
int cnt = 0;
tmp = 0;
while(tmp <= p-q)
{
tmp += x;
x *= 2;
cnt++;
}
//暴力减,触底反弹
int mx = cnt;
mx += min(tmp-(p-q),q);
p -= q;
ans = 0;
//压缩成块
while(p)
{
x = 1;
//块的总减去音量数
b[tp] = 0;
//块中减操作次数
c[tp] = 0;
while(x <= p)
{
p -= x;
b[tp] += x;
c[tp]++;
ans++;
x *= 2;
}
//块下界
a[tp++] = x;
//不是最后一个块,停顿+1
if(p)
{
ans++;
k++;
}
}
//单纯的减操作,停顿存在k中
tmp = ans-k;
int ad = 0;
for(int i = tp-1; i >= 1; --i)
{
//压缩i块与i-1块
ad += a[i-1]-b[i];
tmp -= c[i];
tmp++;
k--;
b[i-1] += a[i-1];
c[i-1]++;
ans = min(ans,tmp+ad+max(0,k-ad));
}
printf("%d\n",min(mx,ans));
}
}
return 0;
}