zoukankan      html  css  js  c++  java
  • 【*篇】SDOI2009 SuperGCD

    特别说明: 为了避免以后搬家时的麻烦, 这里的文章继续沿用csdn的风格和分类好了~

    Emmmm这个题是一道高精度的模板题啊~
    既然是高精度的裸题, 那我们这些懒人当然是选择:用python啦~ 懒癌晚期

    你看这不就做完了么←_←

    a=input()
    b=input()
    while(b):
        c=b
        b=a%b
        a=c
    print a
    

    当然这份代码并不能在luogu上AC 应该是数据出锅了.
    (当然也不能算是出锅, 只是不太符合题目中说的输入格式而已...刻意卡python
    (当然还是有一些python党摸清了读入的规律然后卡过去了 好像rank1就是python吧

    不过毕竟是一道省选题, 如果省选真的碰到了总不能用python写吧(说好的遇到高精的题分就不要了呢
    而且还可以锻炼码力(最后发现并没有
    所以决定用c++写一发.

    而作为STL依赖症的重度患者, 这次的代码直接上了一份

    typedef vector<int> bignum;
    

    不过其实是很方便的_(:з」∠)_ vector莫名其妙的实用, 经常跑得比数组还快, 不知道是怎么做到的.

    然后如果真的按照上面python的代码, 那我们要写一个高精取模. 然而我并不会写.
    这时候就需要用到我们中华民族老祖宗的智慧了——"更相减损之术"!!!

    不过单纯的不优化的更相减损之术是很慢滴, 亲测在不压位的情况下使用可以得到40pts.

    我们可以考虑一个简单易行的, 看上去也很显然的方法:
    我们进行一波分类讨论:

    • (a,b)都是偶数, 那么(gcd(a,b)=2gcd(frac a2,frac b2));
    • (a,b)中有且只有一个偶数, 假如是(a), 那么(gcd(a,b)=gcd(frac a2,b)), 是(b)的话同理;
    • (a,b)都是奇数, 那就更相减损, (gcd(a,b)=gcd(a-b,b)).

    这样的话我们迭代一波(注意不要递归, 递归超级损效率)就可以做了. 我们要做的操作有:
    0. 输入

    1. 判断奇偶
    2. 减法
    3. 除2
    4. 乘2
    5. 输出
      这些都不是很难.. 我们分别做一下就好了.
      这样亲测我们已经能拿到70pts了.

    那剩下30pts怎么找呢? 压位啊~
    没有试压更少的位, 但是压4位已经可以跑得过了...
    压8位的效率似乎提高了一丢丢, 但是还是挺慢的..
    一定是我这个人自带大常数, 无数事实都证明了这一点(明明是你整天用STL...

    然后就是代码了, 可以看到里面有很多实现是挺愚蠢的...(要不然为啥跑得慢呢←_←

    这是压8位的

    // luogu-judger-enable-o2
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N = 1e8;
    typedef vector<int> bignum;
    inline int gcd(int a, int b) {
        if (!b) return a;
        return gcd(b, a%b);
    }
    inline bignum read() {
        bignum a; string s, ss; cin >> s; reverse(s.begin(),s.end());
        while (s.size() > 8) {
            ss = s.substr(0, 8);
            //a.push_back(ss[0] + ss[1] * 10 + ss[2] * 100 + ss[3] * 1000 - 48 * 1111);
            int t = 1, tt = 0;
            for (int i = 0; i < 8; ++i, t *= 10)
                tt += (ss[i] - 48)*t;
            a.push_back(tt);
            s = s.substr(8, s.size());
        } int b = 0; reverse(s.begin(), s.end());
        for (int i = 0; i < s.size(); ++i)
            b = b * 10 + s[i] - 48;
        a.push_back(b);
        return a;
    }
    inline void output(bignum a) {
        int i = a.size() - 1;
        printf("%d", a[i]);
        if (!i) return;
        for (--i; i >= 0; --i)
            printf("%08d", a[i]);
    }
    inline bool iseven(bignum a) {
        return !(*a.begin() & 1);
    }
    inline bool iszero(bignum a) {
        return a.size() == 1 && *a.begin() == 0;
    }
    inline bool bigger(bignum a, bignum b) {
        if (a.size() > b.size()) return 1;
        if (a.size() < b.size()) return 0;
        for (int i = a.size() - 1; i >= 0; --i) {
            if (a[i] > b[i]) return 1;
            if (a[i] < b[i]) return 0;
        }
        return 0;
    }
    inline void delzero(bignum& a) {
        while (a.size() > 1) {
            bignum::iterator it = --a.end();
            if (*it) break;
            a.erase(it);
            it = --a.end();
        }
    }
    inline void sub(bignum &a, bignum b) {
        int i;
        for (i = 0; i < b.size(); ++i) {
            if (a[i] < b[i])
                --a[i + 1], a[i] += N;
            a[i] = a[i] - b[i];
        }
        while (i < a.size() && a[i] < 0)
        {
            a[i] += N;
            ++i;
            --a[i];
        }
        delzero(a);
    }
    inline void half(bignum &a) {
        for (int i = a.size() - 1; i >= 0; --i) {
            if (a[i] & 1)
                a[i - 1] += N;
            a[i] = a[i] >> 1;
        }
        delzero(a);
    }
    inline void doubled(bignum& a) {
        for (int i = 0; i < a.size(); ++i) {
            a[i] <<= 1;
            if (i > 0 && a[i - 1] >= N) a[i - 1] -= N, ++a[i];
        }
        bignum::iterator it = --a.end();
        if (*it >= N) *it -= N, a.push_back(1);
    }
    int main() {
        bignum a = read(), b = read(); int c = 0;
        while (1) {
            if (bigger(b, a)) swap(a, b);
            if (iszero(b)) break;
            if (iseven(a) && iseven(b)) {
                half(a); half(b); ++c;
            }
            else if (iseven(a)) half(a);
            else if (iseven(b)) half(b);
            else sub(a, b);
        }
        for (; c; --c) 
            doubled(a);
        output(a);
    }
    

    这是压4位的(其实差不多, 大约只有输入输出改了的样子)

    #include <cstdio>
    #include <string>
    #include <vector>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N = 1e4;
    typedef vector<int> bignum;
    inline int gcd(int a, int b) {
        if (!b) return a;
        return gcd(b, a%b);
    }
    inline bignum read() {
        bignum a; string s, ss; cin >> s; reverse(s.begin(),s.end());
        while (s.size() > 4) {
            ss = s.substr(0, 4);
            a.push_back(ss[0] + ss[1] * 10 + ss[2] * 100 + ss[3] * 1000 - 48 * 1111);
            s = s.substr(4, s.size());
        } int b = 0; reverse(s.begin(), s.end());
        for (int i = 0; i < s.size(); ++i)
            b = b * 10 + s[i] - 48;
        a.push_back(b);
        return a;
    }
    inline void output(bignum a) {
        int i = a.size() - 1;
        printf("%d", a[i]);
        if (!i) return;
        for (--i; i >= 0; --i)
            printf("%04d", a[i]);
    }
    inline bool iseven(bignum a) {
        return !(*a.begin() & 1);
    }
    inline bool iszero(bignum a) {
        return a.size() == 1 && *a.begin() == 0;
    }
    inline bool bigger(bignum a, bignum b) {
        if (a.size() > b.size()) return 1;
        if (a.size() < b.size()) return 0;
        for (int i = a.size() - 1; i >= 0; --i) {
            if (a[i] > b[i]) return 1;
            if (a[i] < b[i]) return 0;
        }
        return 0;
    }
    inline void delzero(bignum& a) {
        while (a.size() > 1) {
            bignum::iterator it = --a.end();
            if (*it) break;
            a.erase(it);
            it = --a.end();
        }
    }
    inline void sub(bignum &a, bignum b) {
        int i;
        for (i = 0; i < b.size(); ++i) {
            if (a[i] < b[i])
                --a[i + 1], a[i] += N;
            a[i] = a[i] - b[i];
        }
        while (i < a.size() && a[i] < 0)
        {
            a[i] += N;
            ++i;
            --a[i];
        }
        delzero(a);
    }
    inline void half(bignum &a) {
        for (int i = a.size() - 1; i >= 0; --i) {
            if (a[i] & 1)
                a[i - 1] += N;
            a[i] = a[i] >> 1;
        }
        delzero(a);
    }
    inline void doubled(bignum& a) {
        for (int i = 0; i < a.size(); ++i) {
            a[i] <<= 1;
            if (i > 0 && a[i - 1] >= N) a[i - 1] -= N, ++a[i];
        }
        bignum::iterator it = --a.end();
        if (*it >= N) *it -= N, a.push_back(1);
    }
    int main() {
        bignum a = read(), b = read(); int c = 0;
        while (1) {
            if (bigger(b, a)) swap(a, b);
            if (iszero(b)) break;
            if (iseven(a) && iseven(b)) {
                half(a); half(b); ++c;
            }
            else if (iseven(a)) half(a);
            else if (iseven(b)) half(b);
            else sub(a, b);
        }
        for (; c; --c) 
            doubled(a);
        output(a);
    }
    

    嗯, 就这样吧, 完结撒花✿✿ヽ(°▽°)ノ✿

  • 相关阅读:
    [转载][QT][SQL]sql学习记录7_sqlite 日期 & 时间
    [转载][QT][SQL]sql学习记录6_sqlite Autoincrement(自动递增)
    [转载][QT][SQL]sql学习记录5_sqlite视图(View)
    [转载][QT][SQL]sql学习记录4_sqlite约束
    [转载][QT][SQL]sql学习记录3_sqlite之update delete like
    [转载][QT][SQL]sql学习记录2_sqlite数据类型
    [转载][QT][SQL]sq]学习记录1_模糊搜索
    [svn]显示日志很慢 点击文件查看更改记录也贼慢
    [QT]给QApplication安装事件过滤器 app.installEventFilter
    [QT]数据库SQLITE使用错误记录
  • 原文地址:https://www.cnblogs.com/enzymii/p/8409871.html
Copyright © 2011-2022 走看看