HDU 5802 Windows 10

贪心。

p<=q 答案为q-p。下面说p>q的情况。

可以疯狂的减到比q大一点的那个数,然后停顿一下,然后接着减。

也可以减到比q小的最大的那个数,然后再加回来,最后加回来的过程可以用之前停顿的抵消一些。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-8;
void File()
{
    freopen("D:\in.txt","r",stdin);
    freopen("D:\out.txt","w",stdout);
}
inline int read()
{
    char c = getchar();  while(!isdigit(c)) c = getchar();
    int x = 0;
    while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
    return x;
}

int T;
LL b[35],p,q,ans;

void f(LL x,LL sz,LL cnt)
{
    if(x<=q)
    {
        if(cnt>=q-x) ans=min(ans,sz);
        else ans=min(ans,sz+q-x-cnt);
        return;
    }

    int l=1,r=31,pos;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(b[mid]<=x-q) pos=mid,l=mid+1;
        else r=mid-1;
    }

    if(x-b[pos]==q) f(x-b[pos],sz+pos,cnt);
    else
    {
        f(x-b[pos],sz+pos+1,cnt+1);
        f(max((LL)0,x-b[pos+1]),sz+pos+1,cnt);
    }
}

int main()
{
    LL v=1; b[0]=v-1; for(int i=1;i<=31;i++) v=2*v, b[i]=v-1;
    scanf("%d",&T); while(T--)
    {
        scanf("%lld%lld",&p,&q);
        if(p<=q) { printf("%lld
",q-p); continue; }
        ans=1e10; f(p,0,0); printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/5743972.html