• 2018 ACM-ICPC 焦作区域赛 E Resistors in Parallel


    Resistors in Parallel

    Gym - 102028E

    吐槽一下,网上搜索的题解一上来都是找规律,对于我这种对数论不敏感的人来说,看这种题解太难受了,找规律不失为一种好做法,但是题解仅仅包括找规律又有什么意义呢?

    定义

    [f[i] = egin{cases}infin & ext{如果 i 有平方因子, 即$exist d, dge 2$,使得 $i$ 能够被 $d^2$ 整除} \i & otherwiseend{cases} ]

    又定义

    [s[i] = frac{1}{{sum_{d|i}frac{1}{f[d]}}} ]

    给定一个 (n (nle 10^{100})),求(min_{1le ile n} s[i])

    如果 (p) 是一个质数,那么(f[p] = p) , (s[p] = frac{p}{p+1}) , 又可以发现 (s) 是一个积性函数,当(x,y) 互质时,(s(xy) = s(x)s(y)) , (因为(x,y) 除了 1 之外没有公共因子,所以(s(x))(s(y)) 相乘,分母会出现(s(xy)) 的所有分母)。

    而积性函数又有一个性质:如果 (x) 表示为 (x = prod p_i^{c^i}), 那么(s(x) = prod s(p_i^{c_i}))

    然后思考(s(p_i^{c_i})) 的值,由于 (p^2,p^3...p^c) 都是具有平方因子的数字,所以:(s(p^i) = frac{p}{p+1}, forall i in [1,c])

    然后我们思考如何解决这个题,对于任意一个 (x) 都有 (s(x) = prod s(p_i)) 而且 (s(p) lt 1) ,并且随着 (p) 增大 (s(p)) 严格递减,所以:

    [min_{1le i le n} s(i) = prod_{1le ile k} s(p_i),quad ext{并且}prod_{1le i le k}p_i le n ,quad ext{$p_i$ 表示从2开始的第$i$个质数} ]

    另外当 n 等于 1 时,答案为 1。

    所以我们只需要从小到大枚举最多100个数字(因为 n 总共才100位),找到公式描述中的 k,计算答案即可,注意答案中要求输出最简分数,所以在约分可以用一点小技巧(代码中有所体现),当然也可以直接求gcd来化简,但是C++实现的高精度操作除法比较麻烦。

    关于高精度模板:https://www.cnblogs.com/1625--H/p/11141106.html

    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const int N = 100000 + 5;
    int prime[N], m, v[N];
    void init(int n){
        for (int i = 2; i <= n;i++){
            if(!v[i]){
                prime[++m] = i;
            }
            for (int j = 1; j <= m && prime[j] <= n / i;j++){
                v[i * prime[j]] = 1;
                if(i % prime[j] == 0)
                    break;
            }
        }
    }
    struct BigInteger{
        static const int BASE = 10000;
        static const int WIDTH = 4;
        vector<int> s;
        BigInteger(ll num=0) { *this = num; }
        BigInteger(string str) { *this = str; }
        BigInteger(const BigInteger& t) { this->s = t.s; }
        BigInteger operator = (ll num){
            s.clear();
            do{
                s.push_back(num % BASE);
                num /= BASE;
            } while (num > 0);
            return *this;
        }
        BigInteger operator = (string &str){
            s.clear();
            int x, len = (str.length() - 1) / WIDTH + 1;
            for (int i = 0; i < len;i++){
                int end = str.length() - i * WIDTH;
                int start = max(0, end - WIDTH);
                sscanf(str.substr(start, end - start).c_str(), "%d", &x);
                s.push_back(x);
            }
            return *this;
        }
        bool cmp(vector<int> &A, vector<int> &B){
            if(A.size() != B.size())
                return A.size() < B.size();
            for (int i = A.size() - 1; i >= 0;i--){
                if(A[i] != B[i])
                    return A[i] < B[i];
            }
            return false;
        }
        bool operator < (BigInteger & b){
            return cmp(s, b.s);
        }
        bool operator > (BigInteger & b){
            return b < *this;
        }
        bool operator <= (BigInteger &b){
            return !(b < *this);
        }
        bool operator >= (BigInteger &b){
            return !(*this < b);
        }
        bool operator == (BigInteger &b){
            return !(b < *this) && (*this < b);
        }
        vector<int> mul(vector<int>& A, int b);
        BigInteger operator*(int& b);
    };
    ostream& operator << (ostream &out, const BigInteger & x){
        out << x.s.back();
        for (int i = x.s.size() - 2; i >= 0;i--){
            char buf[20];
            sprintf(buf, "%04d", x.s[i]);
            for (int j = 0; j < strlen(buf);j++)
                out << buf[j];
        }
        return out;
    }
    istream& operator>>(istream &in, BigInteger &x){
        string s;
        if(!(in>>s))
            return in;
        x = s;
        return in;
    }
    vector<int> BigInteger::mul(vector<int>&A, int b){
        vector<int> C;
        int t = 0;
        for (int i = 0; i < A.size() || t;i++){
            if(i < A.size())
                t += A[i] * b;
            C.push_back(t % BASE);
            t /= BASE;
        }
        return C;
    }
    BigInteger BigInteger::operator*(int &b){
        BigInteger c;
        c.s = mul(s, b);
        return c;
    }
    int down[N];
    int main() {
        init(100000);
        int T;
        scanf("%d", &T);
        while(T--){
            BigInteger n;
            cin >> n;
            BigInteger acc = 1;
            int pos = 0;
            while(acc * prime[pos + 1] <= n){
                pos++;
                acc = acc * prime[pos];
            }
            for (int i = 1; i <= pos;i++){
                down[i] = prime[i] + 1;
            }
            BigInteger fz = 1, fm = 1;
            for (int i = 1; i <= pos;i++){
                int flag = 0;
                for (int j = 1; j <= pos;j++){
                    if(down[j] % prime[i] == 0){
                        down[j] /= prime[i];
                        flag = 1;
                        break;
                    }
                }
                if(!flag)
                    fz = fz * prime[i];
            }
            for (int i = 1; i <= pos;i++)
                fm = fm * down[i];
            cout << fz << '/' << fm << endl;
        }
        return 0;
    }
    

    贴个 python代码

    N = 100010
    prime = [0 for i in range(N)]
    down = [0 for i in range(N)]
    v = [0 for i in range(N)]
    m = 0
    T = 0
    T = int(input())
    def init(n):
        global m
        for i in range(2, n+1):
            if v[i] == 0 : 
                m = m + 1
                prime[m] = i
            for j in range(1, m+1) :
                if i * prime[j] > n :
                    break
                v[i * prime[j]] = 1
                if i % prime[j] == 0 :
                    break
    maxn = 100000
    init(maxn)
    while T :
        T -= 1
        n = int(input())
        pos = 0
        acc = 1
        while acc * prime[pos+1] <= n :
            pos = pos + 1
            acc = acc *  prime[pos]
        for i in range(1, pos+1):
            down[i] = prime[i] + 1
        fz = 1
        fm = 1
        for i in range(1, pos+1):
            flag = 0
            for j in range(1, pos + 1):
                if down[j] % prime[i] == 0 :
                    down[j] = down[j] // prime[i];
                    flag = 1
                    break
            if flag == 0:
                fz = fz * prime[i]
        for i in range(1, pos+1):
            fm = fm * down[i]
    
        print("%d/%d"%(fz,fm))
    
    
  • 相关阅读:
    ubuntu系统安装Loadrunner压力机和负载端(linux agent)
    LoadRunner生成二进制参数的方法
    [02]树莓派无线USB网卡,Mercury WIFI配置
    6.4节“末端端接器的交流偏置”
    MIPS32的DIV和DIVU实现(除法指令)
    5.3节“开槽地平面的串扰”
    给自己挖坑
    电容降额
    MIPS32的ADDI和ADDIU的实现要点(加法指令)
    使用加法器实现减法
  • 原文地址:https://www.cnblogs.com/1625--H/p/12403316.html
Copyright © 2020-2023  润新知