UOJ 216 Jakarta Skyscrapers

http://uoj.ac/problem/216

题意:给定A,B,C,如果集合中有数i,j(i>j),那么集合就会增加i-j这个数,问有没有在初始集合为{A,B}400步内生成C的方案。

思路:我们用辗转相除法得到gcd(A,B),然后我们用A去减这个GCD,减出"二进制"数,然后就可以组成C了。

由于是log级别的,因此不会有超过400的方案。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<map>
#define ll long long
ll c[50005][2],A,B,C,Gcd;
int tot;
ll read(){
    ll t=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
    return t*f;
}
ll gcd(ll a,ll b){
    if (b==0) return a;
    else return gcd(b,a%b);
}
bool superjudge(){
    if (C>A) {puts("-1");return 1;}
    if (A==C||B==C){puts("0");return 1;}
    ll Gcd=gcd(A,B);
    if (C%Gcd!=0){puts("-1");return 1;}
    return 0; 
}
void work(ll A,ll B,ll C){
    ll t=(A-C)/B,i;
    if (A==C) return;
    c[++tot][0]=A;c[tot][1]=B;
    for (i=1;i*2<=t;i*=2){
        c[++tot][0]=A-i*B;c[tot][1]=i*B;
        c[++tot][0]=A;c[tot][1]=A-2*i*B;
    }
    A-=B*i;
    while (A>C){
        if (A-i*B>=C){
            c[++tot][0]=A;
            c[tot][1]=i*B;
            A-=i*B;
        }
        i/=2;
    }
}
void get_gcd(ll A,ll B){
    if (A==Gcd||B==Gcd) return;
    work(A,B,A%B);
    get_gcd(B,A%B);
}
int main(){
    A=read();B=read();C=read();
    if (A<B)std::swap(A,B);
    if (superjudge()) return 0;
    Gcd=gcd(A,B);
    get_gcd(A,B);
    work(A,Gcd,C);
    printf("%d\n",tot);
    for (int i=1;i<=tot;i++)
     for (i=1;i<=tot;++i) 
      printf("%lld ",c[i][0]),printf("%lld\n",c[i][1]);
}

 

posted @ 2016-07-18 21:43  GFY  阅读(301)  评论(0编辑  收藏  举报