zoukankan      html  css  js  c++  java
  • 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;
    }

     

  • 相关阅读:
    Linux下查看文件和文件夹大小的df和du命令(链接)
    路由的原理和作用[赛迪网]
    select 好用插件
    如何启动/停止/重启MySQL
    Spirng quartz 整合
    String,StringBuffer与StringBuilder的区别
    如何给input[file]定义cursor
    dns简介
    浏览器高级对象
    shell 学习文章列表
  • 原文地址:https://www.cnblogs.com/Willems/p/13802954.html
Copyright © 2011-2022 走看看