题目大意:
给你两个数a,b。然后对于a可以连续进行减操作,每次减操作减去的数为上一次减操作减去的数的2倍,从减1开始,或者也可以对a进行+1操作或者不操作,之后在进行减操作就是重新从减1开始了。
现在有300,000组测试数据,每组测试数据两个数 0 < a,b < 10e9 。
分析:
如果单纯的用搜索,因为有300,000组测试数据,应该就会超时。所以能接受的每一组测试数据的时间复杂度应该就是:O(log|a-b|)。
代码:
#include<iostream>
#include<stdio.h>
#include<queue>
#include<math.h>
using namespace std;
long long int pf[100]={0};//2的i次方=pf[i]
void init()
{
for(int i=0;i<=31;i++)
{
pf[i]=1;
pf[i]=pf[i]<<i;
pf[i]--;
}
}
long long int f(long long int a,long long int b,int x)//从a通过变换规则1到b,在之前已经进行了x次连续加的操作之后,需要操作的最少次数
{
if(a<=b)return (b-a)>(x-1)?(b-a):(x-1);
int t=0;int k=a-b;
while(1)
{
if(k<=pf[t])break;
t++;
}
if(pf[t]==k)return x+t;
//cout<<"min(f("<<a+pf[t]-1<<","<<b<<","<<x+1<<")"<<"+"<<t<<","<<"f("<<a+pf[t-1]-1<<","<<b<<","<<x+1<<")+"<<t-1<<");";
return min(f(0>a-pf[t]?0:(a-pf[t]),b,x+1)+t,f(a-pf[t-1],b,x+1)+t-1);
}
int main()
{
long long int a,b;//从a到b
int n;
init();
scanf("%d",&n);
while(n--)
{
scanf("%lld%lld",&a,&b);
if(a<=b)
{
printf("%lld\n",b-a);
continue;
}
printf("%lld\n",f(a,b,0));
}
}