• AtCoder Beginner Contest 162 C~F


    比赛链接:Here

    AB水题,

    C - Sum of gcd of Tuples (Easy)

    题意:(sum_{a=1}^{K} sum_{b=1}^{K} sum_{c=1}^{K} g c d(a, b, c))

    数据范围:(1le Kle 200)

    思路:因为 (k) 比较小,我们直接跑暴力即可

    int main() {
        ios::sync_with_stdio(false), cin.tie(nullptr);
        ll n; cin >> n;
        ll ans = 0;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                for (int k = 1; k <= n; k++)
                    ans += __gcd(__gcd(i, j), k);
        cout << ans;
    }
    

    D - RGB Triplets

    题意:给一个长度为N的字符串S,只包含'R','B','G'。求有多少个三元组 ((i,j,k)(1le i<j<kle N)) 满足 (S_{i} eq S_{j}, S_{i} eq S_{k}, S_{j} eq S_{k}, j-i eq k-j_{circ})

    数据范围:(1le N le 4000)

    题解:先将满足 (_{i} eq S_{j}, S_{i} eq S_{k}, S_{j} eq S_{k}) 的算出来,在减去 (j-i eq k-j) 的数目。

    总的显然等于 (num(R)*num(B)*num(G)) ,然后枚举两个端点,判断第三个端点是不是不同于这个两个端点的颜色。

    const int N = 4e3 + 5;
    int main() {
        ios::sync_with_stdio(false), cin.tie(nullptr);
        int n; string s;
        cin >> n >> s;
        int a = 0, b = 0, c = 0;
        for (int i = 0; i < n; ++i) {
            if (s[i] == 'R') a += 1;
            if (s[i] == 'G') b += 1;
            if (s[i] == 'B') c += 1;
        }
        ll ans = 1ll * a * b * c;
        for (int i = 0; i < n; i++)
            for (int j = i + 1; j < n; j++) {
                if (s[i] == s[j]) continue;
                if (2 * j - i < n && s[i] != s[2 * j - i] && s[j] != s[2 * j - i]) ans--;
            }
        cout << ans;
    }
    

    E - Sum of gcd of Tuples (Hard)

    题意:(sum_{a_{1}=1}^{K} sum_{a_{2}=1}^{K} ldots sum_{a_{N}=1}^{K} g c dleft(a_{1}, a_{2}, ldots, a_{N} ight)(mod 1 mathrm{e} 9+7))

    数据范围:(2 leq N leq 10^{5}, 1 leq K leq 10^{5})

    思路一:莫比乌斯反演化简

    [egin{array}{l} A n s=sum_{a_{1}=1}^{K} sum_{a_{2}=1}^{K} ldots sum_{a_{N}=1}^{K} g c dleft(a_{1}, a_{2}, ldots, a_{N} ight) \ =sum_{i=1}^{K} sum_{a_{1}=1}^{K} sum_{a_{2}=1}^{K} ldots sum_{a_{N}=1}^{K} ileft[operatorname{gcd}left(a_{1}, a_{2}, ldots, a_{N} ight)==i ight] \ =sum_{i=1}^{K} sum_{a_{1}=1}^{leftlfloorfrac{K}{i} ight floor} sum_{a_{2}=1}^{leftlfloorfrac{K}{i} ight floor} ldots sum_{a_{N}=1}^{leftlfloorfrac{K}{i} ight floor} ileft[operatorname{gcd}left(a_{1}, a_{2}, ldots, a_{N} ight)==1 ight] \ =sum_{i=1}^{K} sum_{a_{1}=1}^{leftlfloorfrac{K}{i} ight floor} sum_{a_{2}=1}^{leftlfloorfrac{K}{i} ight floor} ldots sum_{a_{N}=1}^{leftlfloorfrac{K}{i} ight floor} i sum_{d=1}^{leftlfloorfrac{K}{i} ight floor} mu(d)leftlfloorfrac{d}{a_{1}} ight floorleftlfloorfrac{d}{a_{2}} ight floor ldotsleftlfloorfrac{d}{a N} ight floor \ =sum_{i=1}^{K} i sum_{d=1}^{leftlfloorfrac{K}{imath} ight floor} mu(d) sum_{a_{1}=1}^{leftlfloorfrac{K}{i d} ight floor} sum_{a 2=1}^{leftlfloorfrac{K}{i d} ight floor} ldots sum_{a N=1}^{leftlfloorfrac{K}{i d} ight floor} 1 \ =sum_{i=1}^{K} i sum_{d=1}^{leftlfloorfrac{K}{i} ight floor} mu(d)leftlfloorfrac{K}{i d} ight floor^{N} \ =sum_{T=1}^{K}leftlfloorfrac{K}{T} ight floor^{N} sum_{d mid T} mu(d) *leftlfloorfrac{T}{d} ight floor(T=i d) \ =sum_{T=1}^{K}leftlfloorfrac{K}{T} ight floor^{N} phi(T) end{array} ]

    由于 (K) 不大,预处理欧拉函数,直接遍历即可。(K) 大的话,整除分块加杜教筛(雾。

    #include <bits/stdc++.h>
    using ll = long long;
    using namespace std;
    const int N = 1e5 + 5, MD = 1e9 + 7;
    int pri[N], tot, phi[N];
    bool p[N];
    void init() {
        p[1] = true, phi[1] = 1;
        for (int i = 2; i < N; i++) {
            if (!p[i]) pri[++tot] = i, phi[i] = i - 1;
            for (int j = 1; j <= tot && i * pri[j] < N; j++) {
                p[i * pri[j]] = true;
                if (i % pri[j] == 0) {
                    phi[i * pri[j]] = phi[i] * pri[j];
                    break;
                } else phi[i * pri[j]] = phi[i] * (pri[j] - 1);
            }
        }
    }
    ll qpow(ll a, ll b) {
        ll ans = 1;
        for (; b; b >>= 1, a = a * a % MD) if (b & 1) ans = ans * a % MD;
        return ans;
    }
    void add(int &x, int y) { x += y; if (x >= MD) x -= MD;}
    int main() {
        ios::sync_with_stdio(false), cin.tie(nullptr);
        init();
        int n, k, ans = 0;
        cin >> n >> k;
        for (int i = 1; i <= k; i++)
            add(ans, 1LL * qpow(k / i, n)*phi[i] % MD);
    
        cout << ans;
    }
    

    思路二:

    学习了下官方题解:定义 (f[i]) 代表 (gcd)(i) 的个数,递推关系式:(f[i]=leftlfloorfrac{K}{i} ight floor^{N}-sum_{j>i, i mid j} f[j]_{circ})

    双重循环即可,里面那层循环的复杂度总和是个调和级数,(log) 级别的。

    const int N = 1e5 + 5, MD = 1e9 + 7;
    int f[N];
    ll qpow(ll a, ll b) {
        ll ans = 1;
        for (; b; b >>= 1, a = a * a % MD) if (b & 1) ans = ans * a % MD;
        return ans;
    }
    void add(int &x, int y) {
        x += y;
        if (x >= MD) x -= MD;
        if (x < 0) x += MD;
    }
    int main() {
        ios::sync_with_stdio(false), cin.tie(nullptr);
        int n, k;
        scanf("%d%d", &n, &k);
        cin >> n >> k;
        for (int i = k; i >= 1; i--) {
            f[i] = qpow(k / i, n);
            for (int j = 2 * i; j <= k; j += i)
                add(f[i], -f[j]);
        }
        int ans = 0;
        for (int i = 1; i <= k; i++)
            add(ans, 1LL * f[i]*i % MD);
    
        cout << ans;
    }
    

    F - Select Half

    题意:给一个长度为 (N) 的序列 (A),要求选 (left[frac{N}{2} ight floor) 个数,且下标互不相邻,最大化它们的总和。

    数据范围:(2le Nle 2 imes 10^5)

    题解:对于选的数的下标, (B_{1}, B_{2} ldots, B_{leftlfloorfrac{N}{2} ight floor}),可以发现 (sum_{i=2}^{leftlfloorfrac{N}{2} ight floor} B_{i}-B_{i-1}-2 leq 2)

    因此定义 (f[i][j])​ 代表选第 (1~i) 里面的数(必选第个 (i) 数),前面多空了 (j) 的最大值。

    [left{egin{aligned} f[i][0] &=f[i-2][0]+a[i] \ f[i][1] &=max (f[i-2][1], f[i-3][0])+a[i] \ f[i][2] &=max (f[i-2][2], f[i-3][1], f[i-4][0])+a[i] end{aligned} ight. ]

    const int N = 2e5 + 5;
    int a[N];
    ll f[N][3];
    int main() {
        ios::sync_with_stdio(false), cin.tie(nullptr);
        int n; cin >> n;
        for (int i = 1; i <= n; ++i) cin >> a[i];
        for (int i = 1; i <= n; i++)
            for (int j = 0; j < 3; j++)
                f[i][j] = -1e18;
    
        for (int i = 1; i <= 3; i++)
            f[i][i - 1] = a[i];
    
        f[3][0] = a[1] + a[3];
        for (int i = 4; i <= n; i++) {
            f[i][0] = f[i - 2][0] + a[i];
            f[i][1] = max(f[i - 2][1], f[i - 3][0]) + a[i];
            f[i][2] = max(f[i - 2][2], f[i - 3][1]) + a[i];
            if (i > 4) f[i][2] = max(f[i][2], f[i - 4][0] + a[i]);
        }
        ll ans;
        if (n & 1) ans = max(f[n][2], max(f[n - 1][1], f[n - 2][0]));
        else
            ans = max(f[n][1], f[n - 1][0]);
        cout << ans;
    }
    

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    111
    python 错误宝典
    Node.js Web开发:Connect
    Node.js 中的重要API:HTTP
    Node.js 中的重要API:TCP
    Node.js 中的重要API:命令行工具以及FS API 首个Node应用
    Node.js 中的JS
    Node.js 阻塞式IO与非阻塞式IO与错误处理
    Learning Vue.js 2
    A1046——入门模拟 Shortest Distance
  • 原文地址:https://www.cnblogs.com/RioTian/p/15247349.html
Copyright © 2020-2023  润新知