Codeforces Global Round 11 E.Xum (exgcd,构造,思维)

题目:传送门

题意

给你一个序列,序列里一开始只有一个奇数 x,你可以对这个序列进行两种操作:

1.选择两个序列里的数 x, y(两个数可以相等,且只要序列里出现过就可以选择两次),向序列里面加入 x + y

2.选择两个序列里的数 x, y(两个数可以相等,且只要序列里出现过就可以选择两次),向序列里面加入 x ^ y

问怎样操作后,序列里出现1.

思路

官方题解

对于输入的 x,我们可以构造一个 y,使得 gcd(x,y) = 1;然后我们可以通过扩展欧几里得,求 ax - by = 1 的一组解,这里 a,b >= 0 且 b 是偶数,那么 ax = by + 1; 则 ax ^ by = 1,就成功构造出了 1;

#include <bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define UI unsigned int
#define mem(i, j) memset(i, j, sizeof(i))
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define pb push_back
#define make make_pair
#define INF 0x3f3f3f3f
#define inf LLONG_MAX
#define PI acos(-1)
#define fir first
#define sec second
#define lb(x) ((x) & (-(x)))
#define dbg(x) cout<<#x<<" = "<<x<<endl;
using namespace std;

const int N = 1e6 + 5;

LL x;

struct note {

    LL x, op, y;

};

vector < note > ans;

void exgcd(LL a, LL b, LL &x, LL &y) {

    if(!b) {

        x = 1; y = 0;

        return ;

    }

    exgcd(b, a % b, y, x);

    y -= a/b*x;

}

void ks_add(LL a, LL b) {

    LL res = -1;

    while(b) {

        if(b & 1) {

            if(res == -1) res = a;

            else {

                ans.pb({res, 0, a});

                res += a;

            }

        }

        ans.pb({a, 0, a});

        a += a;

        b >>= 1;

    }

}

void solve() {

    scanf("%lld", &x);

    LL now = 1;

    while(2LL * now < x) {

        ans.pb({now * x, 0, now * x});

        now *= 2LL;

    }

    ans.pb({x, 1, now * x});

    LL y = (x ^ (now * x));

    LL a, b;

    exgcd(x, y, a, b); /// 这里求得 ax + by = 1 的一组解 a, b,由于 x,y > 1,则 a, b必定一正一负

    /// 由于我们要求的是 ax - by = 1 的解,故让 b *= -1; 然后判 a 是否大于 0

    b = -b;

    if(a <= 0) {

        LL c = (-a) / y + 1;

        a += c * y;

        b += c * x;

    }
    
    /// b 是偶数,能保证 by 是一个偶数,这样 ax ^ by 才会等于 1
    
    if(b & 1) a += y, b += x;

    ks_add(x, a);

    ks_add(y, b);

    ans.pb({a * x, 1, b * y});

    printf("%d
", (int)ans.size());

    for(auto v : ans) {

        printf("%lld %c %lld
", v.x, "+^"[v.op], v.y);

    }

}


int main() {

//    int _; scanf("%d", &_);
//    while(_--) solve();

    solve();

    return 0;
}

 

原文地址:https://www.cnblogs.com/Willems/p/13802954.html