Windows 10
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1276 Accepted Submission(s): 434
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.
Next T line,each line contains two numbers p and q (0 <= p,q <= 1e9)
2 1 5 7 3
4 4
这是一道神奇的题目,我表示当时其实大概明白怎么做了,但是一直wa一直wa,里面好几个变量进入递归过程的时候我控制不好,思维不清晰导致很晕。实在是混得不行,我还是默默的看了标程。。。标程十分简短,就十行多,清晰易懂,所以说,优美的代码是成功AC的第一步。
题意就是,要求P到Q的最小秒数。这个过程中有一个要点,1,上升的话只能一个一个上升,2,连续下降的话,本一次的下降量是上一次的2倍,也就相当于1,2,4,8这样减下去,但是这个是可以中断的,你可以选择休息一秒,那么下降量就归零,也可以选择上升一格,清空下降量。其中有个关键就是,比如你现在是7,下一次是下降8,那么不会变成-1,而是会变成0的。
这道题第一次看到的时候,默认想到的是BFS,但是BFS冗余量太大,会完美超时,分析分析看看,Q大于P的话,直接相减输出。P>Q下降的话,其实只有两种走法,一种是下降到恰好比Q小,然后往回升,一种是下降到恰好比Q大,清除一下下降量,再下降,这样循环。所以我们可以用递归来写,用DFS。每次下降到恰好比Q小,算一下加上上升所需要的步数,与Min比较一下。得到恰好比Q大的数字,进入下一次递归。
你需要去记录停顿了多少次,因为你停顿的时候是浪费掉的,还不如去补偿上升的步数呢,因为你上升也是可以消除下降步数的。
所以,代码如下,还是很乱的,在原来wa的代码上修改一下就过了
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<set>
using namespace std;
int p,q,k;
long long Min;
void dfs(long long x,int n)
{
int i = 0;
int t = 1;
long long sum = 1;
int cout, add;
if(x - sum == q)//如果恰好等于了,就可以直接返回结束了
{
if(n + 1 < Min)//以前所经过的次数n次加上执行了i+1次就是这次所使用的次数
Min = n + 1;
return;
}
while(x - sum > q)//使劲往下降,等于的话会在循环内检测出来,如果小于的话就跳出
{
t *= 2;
i++;//说明t是2的i次方
sum += t;
}
if(x - sum < 0)//如果x-sum小于了0,那么就会自动变成0,所增加的次数就是q减去0
add = q - 0;
else//如果没有小于0,那就可以直接算出q和(s-sum)的差
add = q - (x - sum);
add = add - k <= 0 ? 0 : add - k;
cout = add + i + n + 1;//总共的次数
if(cout < Min)
Min = cout;
k++;//这个是停顿的次数
dfs(x - (sum - t), n + i + 1);//i+1是这次循环所用的次数
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d", &p, &q);
if(p <= q)
printf("%d\n",q - p);
else
{
Min = 99999999;
k = 0;
dfs(p, 0);
printf("%lld\n",Min);
}
}
return 0;
}