这道题,首先想到的就是BFS,但是因为数据太大,BFS不仅TLE而且MLE。
我是这么思考的:
如果n >= m 显然只能是1步1步减,输出n-m即可。
如果m > n ,也就是说m经过若干步骤后变成了n。
我们假设m的变化中第2次变化有*2操作,那么在下面的情况里不可能出现相邻连续+1+1或者-1-1,如果出现,只要先+1或-1再*2即可。
eg. 6 ->14 6 * 2 = 12 12 + 1 + 1 = 14 ; 3步
6 + 1 = 7 7 * 2 = 14 ; 2步
有了这一点,不难想到此题我们考虑从n到m,一开始只有1个偶数(或者奇数)扩展相邻项后最多每层只有2个偶数,那么一共有log(2,1e500)层(不到2000层),
每层2个数,那就没压力了。然后记下每层的到达这个数的最小步数(相邻则进行更新)。
eg. m = 801 n = 5
第一层 800 801 802
步数 1 0 1 更新ans = 801 -5=796
第二层 400 402 更新ans
……
提交后的测试期望时间是78MS
<pre name="code" class="cpp">/*
* Author:
* OpenPandora
* Date:
* 2014.08.26
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define cls(a) memset(a,0,sizeof(a))
#define rise(i,a,b) for(int i=a;i<=b;i++)
#define fall(i,a,b) for(int i=a;i>=b;i--)
const int base = 1e9;
char a[600];
bool ined, flag;
int cnt, cntt, ep;
void init()
{
ined = false; cnt = 0;
while( true )
{
a[cnt] = getchar();
if( a[cnt] >= '0' && a[cnt] <= '9' )
{
ined = true;
cnt ++;
}
else if( ined ) break;
}
a[cnt] = '\0';
cnt --;
}
struct point
{
int num[60], len;
point() { clear(); }
void clear(){ len = 1 ; cls(num); }
void out( int x )
{
printf( "%d" , num[len] );
fall( i , len - 1 , 1 ) printf( "%09d" , num[i] );
if( x )putchar('\n');
else putchar( ' ' );
}
void in()
{
init(); cntt = 0; ep = 1; clear();
fall( i , cnt , 0 )
{
if( cntt == 9 )
{
cntt = 0;
len ++;
ep = 1;
}
cntt ++;
num[len] += (int) ( a[i] - '0' ) * ep;
ep *= 10;
}
while( len > 1 && num[len] == 0 ) len --;
}
void inc()
{
num[1] ++;
rise( i , 1 , len )
{
if( num[i] >= base )
{
num[i+1] ++;
num[i] -= base;
}
else break;
}
if( num[len+1] == 1 ) len ++;
}
void dec( int x )
{
num[1] -=x;
rise( i , 1 , len )
{
if( num[i] < 0 )
{
num[i+1] --;
num[i] += base;
}
else break;
}
if( num[len] == 0 ) len --;
}
void divid()
{
fall( i , len , 1 )
{
num[i-1] += ( num[i] & 1 ) * base;
num[i] >>= 1;
}
if( num[len] == 0 ) len --;
}
point &operator = ( const point& );
point operator - ( const point& )const;
point operator + ( const point& )const;
point(const int);
bool operator>(const point &p )const;
bool operator<(const point &p )const;
bool operator==(const point &p )const;
}n, m, one, zero, two, now[3], tmp[5], nv[3], tv[5], ans;
point & point :: operator=(const point &p)
{
clear();
len = p.len;
rise( i , 1 , len ) num[i] = p.num[i];
return *this;
}
point point ::operator+(const point &p)const
{
point ret = *this;
int l = max( ret.len , p.len );
rise( i , 1 , l )
{
ret.num[i] += p.num[i];
if( ret.num[i] >= base )
{
ret.num[i+1] ++;
ret.num[i] -= base;
}
}
if( ret.num[l+1] > 0 ) l ++;
ret.len = l;
return ret;
}
point point ::operator-(const point &p)const
{
point ret = *this;
if( ret > p )
{
rise( i , 1 , ret.len )
{
ret.num[i] -= p.num[i];
if( ret.num[i] < 0 )
{
ret.num[i] += base;
ret.num[i+1] --;
}
}
while( ret.len > 1 )
if( ret.num[ret.len] == 0 ) ret.len --;
else break;
return ret;
}
if( ret == p )
return zero;
if( ret < p )
{
point tmp = ret;
ret = p;
rise( i , 1 , ret.len )
{
ret.num[i] -= tmp.num[i];
if( ret.num[i] < 0 )
{
ret.num[i] += base;
ret.num[i+1] --;
}
}
while( ret.len > 1 )
if( ret.num[ret.len] == 0 ) ret.len --;
else break;
return ret;
}
}
point::point( const int b )
{
clear();
num[1] = b;
}
bool point::operator==(const point &p)const
{
if( len != p.len ) return false;
fall( i , len , 1 ) if( num[i] != p.num[i] ) return false;
return true;
}
bool point::operator>(const point &p)const
{
if( len > p.len ) return true;
if( len < p.len ) return false;
fall( i , len , 1 )
{
if( num[i] > p.num[i] ) return true;
if( num[i] < p.num[i] ) return false;
}
return false;
}
bool point::operator<(const point &p)const
{
if( len < p.len ) return true;
if( len > p.len ) return false;
fall( i , len , 1 )
{
if( num[i] < p.num[i] ) return true;
if( num[i] > p.num[i] ) return false;
}
return false;
}
int main()
{
one = point(1);
zero = point(0);
two = point(2);
int cnt = 1;
while( true )
{
m.in();
n.in();
if( n == zero && m == zero ) break;
if( n > m || n == m )
{
( n - m ).out(1);
continue;
}
now[1] = m;
ans = m - n;
cnt = 1;cntt=0;
while( cnt )
{
rise( i , 1 , cnt )
{
if( ans > now[i] - n + nv[i] ) ans = now[i] - n + nv[i];
if( now[i].num[1] % 2 == 0 )
{
flag = 0;
rise( j , 1 , cntt )
if( now[i] == tmp[j] )
{
if( nv[i] < tv[j] )
tv[j] = nv[i];
flag = true;
}
if( !flag )
{
tmp[++cntt] = now[i];
tv[cntt] = nv[i];
}
}
else
{
nv[i].inc();
flag = false;
now[i].inc();
rise( j , 1 , cntt )
if( now[i] == tmp[j] )
{
if( nv[i] < tv[j] )
tv[j] = nv[i];
flag = true;
}
if( !flag )
{
tmp[++cntt] = now[i];
tv[cntt] = nv[i];
}
if( now[i] > two )
{
flag = false;
now[i].dec(2);
rise( j , 1 , cntt )
if( now[i] == tmp[j] )
{
if( nv[i] < tv[j] )
tv[j] = nv[i];
flag = true;
}
if( !flag )
{
tmp[++cntt] = now[i];
tv[cntt] = nv[i];
}
}
}
now[i].clear();
nv[i].clear();
}
cnt = 0;
rise( i , 1 , cntt )
{
if( ( tmp[i].len > 1 || tmp[i].num[1] > 2 ) && tmp[i] > n )
{
tmp[i].divid();
nv[++cnt] = tv[i] + one;
now[cnt] = tmp[i];
}
tmp[i].clear();
tv[i].clear();
}
cntt = 0;
}
ans.out(1);
}
return 0;
}