2020牛客暑期多校训练营(第四场)B、F、H题解及补题

2020牛客暑期多校训练营(第四场)题解及补题

比赛过程

一共出了三题。依次为BFH,这次吸取教训,前期求稳了,也得到了稳的好处,罚时相对低了。

题解

A

题意
解法
代码

B

题意

给出定义 f c ( x ) = max ⁡ 1 < i < x − 1 c ⋅ f c ( g c d ( i , x ) ) , x > 1 ; f c ( x ) = 1 , x = 1 f_c(x)=\max\limits_{1< i < x-1} c\cdot f_c(gcd(i,x)),x>1;f_c(x)=1,x=1 fc(x)=1<i<x1maxcfc(gcd(i,x)),x>1;fc(x)=1,x=1。问给定的n,c下最大的 f c ( n ) f_c(n) fc(n)

解法

容易发现,最后答案即为 c i c^i ci的形式,容易证明i的最大值即质因子的指数和。

代码
#include <stdio.h>

#include <algorithm>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const ll maxn = 1e6 + 111;
const ll mod = 1e9 + 7;
ll v[maxn] = {0}, prime[maxn], m = 0;  // v为最小质因子 v==i则为质数 1看情况取
void primes(ll n) {
    for (ll i = 2; i <= n; ++i) {
        if (!v[i]) {  // i为质数
            v[i] = i;
            prime[++m] = i;
        }
        //给当前的数i乘上一个质因子
        for (ll j = 1; j <= m; ++j) {
            // i有比prime[j]更小的质因子,或者超出n的范围
            if (prime[j] > v[i] || prime[j] * i > n) break;
            // prime[j]是合数i*prime[j]的最小质因子
            v[i * prime[j]] = prime[j];
        }
    }
}
ll qm(ll a, ll b, ll mod) {
    ll ret = 1, cnt = a;
    while (b) {
        if (b & 1) {
            ret = ret * cnt % mod;
        }
        cnt = cnt * cnt % mod;
        b >>= 1;
    }
    return ret;
}
int main() {
    v[1] = 1;
    primes(1000000);
    ll T;
    scanf("%lld", &T);
    while (T--) {
        ll n, c;
        scanf("%lld%lld", &n, &c);
        ll cnt = 0;
        while (n != 1) {
            n /= v[n];
            ++cnt;
        }
        printf("%lld\n", qm(c, cnt, mod));
    }
    return 0;
}

C

题意
解法
代码

D

题意
解法
代码

E

题意
解法
代码

F

题意

两条平行线AB,CD。给出长度AC,AD,BC,BD,问以AB为参照下,C在D前还是后。

解法

分类讨论,总共分成四种情况,分别算出这些情况下的长度相对关系,然后由对称性质可证其正确性。

代码
#include <stdio.h>

#include <algorithm>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const ll maxn = 1e6 + 111;
const ll mod = 1e9 + 7;
int main() {
    ll T;
    scanf("%lld", &T);
    while (T--) {
        ll ac, ad, bc, bd;
        cin >> ac >> ad >> bc >> bd;
        int flag = 0;
        if (ac > ad && bc > bd && ac < bc && ad < bd) {
            flag = 1;
        } else if (ac < ad && bc < bd && ac > bc && ad > bd) {
            flag = 1;
        } else if (ac <= ad && bc >= bd) {
            flag = 1;
        } else if (ac <= bc && ad >= bd) {
            flag = 1;
        } else {
        }
        if (flag) {
            puts("AB//CD");
        } else {
            puts("AB//DC");
        }
    }
    return 0;
}

G

题意
解法
代码

H

题意

给出一个整数n,问1到n的点最多多少个非互质点对。

解法

以因子中最小质数为标识区分这些数,然后从大到小遍历,如果数量为偶数,内部匹配,否则,从2中拉来一个凑数。

代码
#include <stdio.h>

#include <algorithm>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const ll maxn = 1e6 + 111;
const ll mod = 1e9 + 7;
ll v[maxn] = {0}, prime[maxn], m = 0;  // v为最小质因子 v==i则为质数 1看情况取
void primes(ll n) {
    for (ll i = 2; i <= n; ++i) {
        if (!v[i]) {  // i为质数
            v[i] = i;
            prime[++m] = i;
        }
        //给当前的数i乘上一个质因子
        for (ll j = 1; j <= m; ++j) {
            // i有比prime[j]更小的质因子,或者超出n的范围
            if (prime[j] > v[i] || prime[j] * i > n) break;
            // prime[j]是合数i*prime[j]的最小质因子
            v[i * prime[j]] = prime[j];
        }
    }
}
vector<ll> fac[200000];
ll flag[maxn];
int main() {
    ll T;
    primes(200000);
    scanf("%lld", &T);
    while (T--) {
        ll n;
        scanf("%lld", &n);
        vector<ll> vec;
        for (ll i = 1; i <= n; ++i) {
            flag[i] = 0;
            fac[i].clear();
        }
        for (ll i = 2; i <= n; ++i) {
            if (v[i] == i) {
                if (i * 2 > n) break;
                vec.push_back(i);
                fac[i].push_back(i);
                ll cnt = i;
                ll add = 1;
                if (i > 2) add = 2;
                while (cnt * i <= n) {
                    if (v[cnt] < i) {
                        cnt += add;
                        continue;
                    }
                    fac[i].push_back(cnt * i);
                    cnt += add;
                }
            }
        }
        reverse(vec.begin(), vec.end());
        ll numm = 0;
        for (auto w : vec) {
            numm += fac[w].size();
        }
        printf("%lld\n", numm / 2);
        for (auto w : vec) {
            if (w == 2) {
                ll cnt = 0;
                ll ans[2];
                for (auto ww : fac[2]) {
                    if (flag[ww]) continue;
                    ans[cnt++] = ww;
                    if (cnt == 2) {
                        printf("%lld %lld\n", ans[0], ans[1]);
                        cnt = 0;
                    }
                }
            } else {
                ll i = 0;
                if (fac[w].size() & 1) {
                    flag[2 * w] = 1;
                    printf("%lld %lld\n", w, 2 * w);
                    i = 1;
                }
                ll rr = fac[w].size();
                for (; i < rr; i += 2) {
                    printf("%lld %lld\n", fac[w][i], fac[w][i + 1]);
                }
            }
        }
    }
    return 0;
}

I

题意
解法
代码

J

题意
解法
代码

K

题意
解法
代码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值