AtCoder Beginner Contest 162 C~F

比赛链接:Here

AB水题,

C - Sum of gcd of Tuples (Easy)

题意:a=1Kb=1Kc=1Kgcd(a,b,c)

数据范围:1K200

思路:因为 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)(1i<j<kN) 满足 SiSj,SiSk,SjSk,jikj

数据范围:1N4000

题解:先将满足 iSj,SiSk,SjSk 的算出来,在减去 jikj 的数目。

总的显然等于 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)

题意:a1=1Ka2=1KaN=1Kgcd(a1,a2,,aN)(mod1e9+7)

数据范围:2N105,1K105

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

Ans=a1=1Ka2=1KaN=1Kgcd(a1,a2,,aN)=i=1Ka1=1Ka2=1KaN=1Ki[gcd(a1,a2,,aN)==i]=i=1Ka1=1Kia2=1KiaN=1Kii[gcd(a1,a2,,aN)==1]=i=1Ka1=1Kia2=1KiaN=1Kiid=1Kiμ(d)da1da2daN=i=1Kid=1Kıμ(d)a1=1Kida2=1KidaN=1Kid1=i=1Kid=1Kiμ(d)KidN=T=1KKTNdTμ(d)Td(T=id)=T=1KKTNϕ(T)

由于 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] 代表 gcdi 的个数,递推关系式:f[i]=KiNj>i,ijf[j]

双重循环即可,里面那层循环的复杂度总和是个调和级数,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,要求选 [N2 个数,且下标互不相邻,最大化它们的总和。

数据范围:2N2×105

题解:对于选的数的下标, B1,B2,BN2,可以发现 i=2N2BiBi122

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

{f[i][0]=f[i2][0]+a[i]f[i][1]=max(f[i2][1],f[i3][0])+a[i]f[i][2]=max(f[i2][2],f[i3][1],f[i4][0])+a[i]

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;
}
posted @   RioTian  阅读(73)  评论(0编辑  收藏  举报
编辑推荐:
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
阅读排行:
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· 分享4款.NET开源、免费、实用的商城系统
· 解决跨域问题的这6种方案,真香!
· 一套基于 Material Design 规范实现的 Blazor 和 Razor 通用组件库
· 5. Nginx 负载均衡配置案例(附有详细截图说明++)
历史上的今天:
2020-09-09 CF(codeforces)如何保持紫名及以上?
2020-09-09 Codeforces Round #669 (Div. 2) A、B题题解
点击右上角即可分享
微信分享提示

📖目录