AtCoder Beginner Contest 393 题解

题目地址:https://atcoder.jp/contests/abc393

A - Poisonous Oyster

分支判断

#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;



inline void init()
{
    string s1, s2;cin >> s1 >> s2;
    if(s1 == s2 && s1 == "fine")cout << 4;
    else if(s1 == s2 && s1 == "sick")cout << 1;
    else if(s1 == "fine" && s2 == "sick")cout << 3;
    else cout << 2;
}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    return 0;
}

B - A…B…C

#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;



inline void init()
{
    string s; cin >> s;
    int len = s.length();
    int ans = 0;
    for(int i = 0; i < len - 2; i ++)// 枚举A
    {
        if(s[i] != 'A')continue;
        for(int j = i + 1; j < len - 1; j ++)// 枚举B
        {
            if(s[j] != 'B')continue;
            if(j + j - i >= len)break;
            if(s[j + j - i] == 'C')ans ++;// 判断C
        }
    }
    cout << ans << endl;
}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    return 0;
}

C - Make it Simple

给一个无向图,要求删除所有自循环和多条边。给出一条边u=v时,直接ans++。对于没有出现的边,可以维护一个map数组,令map[u][v] = map[v][u] = 1,标记该条边。对于被标记的边直接ans++

#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;

const int N = 2e5 + 9;
map<int, int> mp[N];

inline void init()
{
    int n, m;cin >> n >> m;
    int ans = 0;
    for(int i = 1; i <= m; i ++)
    {
        int u, v;cin >> u >> v;
        if(u == v)ans ++;
        else
        {
            if(mp[u][v])ans ++;
            else mp[u][v] = mp[v][u] = 1;
        }
    }
    cout << ans << endl;
}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    return 0;
}

D - Swap to Gather

题目要求通过相邻元素换位来使得所有的1在一起,求最少操作数。类似寻找1的重心,但分析1的移动较为困难,可分析0,那题目就转变为将所有0移到1的左边或右边
迎面就有一个问题:对于一个0,感性的想一定是一路向左或向右移花费最少,那是应该往左移还是右移?例如110111,应该向左移动两位,即1少的一边移动。并且不难发现移动次数对应着移动方向的1的个数,这是正确的,感性的想:对于每个0都需要移到所有1的外边,移动次数就是一定不少于该侧1的个数。来个例子:111101011,0和0的换位是没有意义的,所以最优的,我们可以先移动靠右边的0两次,再移动靠左的0三次,那么答案就是1的数之和。

代码实现上,需要对于每个0快速得出其左右的1的个数,我们可以遍历01串,实时记录当前1的个数,遍历到0时就查询cnt和1的总数 - cnt

#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;

const int N = 5e5 + 9;

inline void init()
{
    int _;cin >> _;
    string s;cin >> s;
    int n = 0, cnt = 0, ans = 0;
    for(const auto &i : s)
        if(i == '1')
            n ++;
    for(const auto &i : s)
    {
        if(i == '1')cnt ++;
        else ans += min(cnt, n - cnt);
    }
    cout << ans << endl;
}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    return 0;
}

E - GCD of Subset

要求找包含ai的k个数字的最大公约数,暴力、直觉思路枚举ai,发现k有多少,就会有多少个for循环,复杂度接受不了。既然枚举数算公约数不行,考虑直接枚举答案,也就是枚举因子公约数最小是1,最大不超过数组中的最大值,答案就是1到mx。
题目还要求找k个,

未完结,之后再补

// #include <bits/stdc++.h>
// #define int long long
// #define endl "\n"
// using namespace std;
//
// const int N = 1.2 * 1e6 + 9;
// int a[N], vis[N], mul[N], ans[N];
//
// inline void init()
// {
//     int n, k;cin >> n >> k;
//     for(int i = 1; i <= n; i ++)cin >> a[i];
//     for(int i = 1; i <= n; i ++)// On
//     {
//         for(int j = 2; j <= a[i]; j ++)// Om
//         {
//             if(a[i] % j)continue;
//             // 若j可以为答案,说明还有k-1个数是j的倍数
//             // 记忆化遍历,需要j->是j倍数的个数
//             if(!vis[j])
//             {
//                 vis[j] = 1;
//                 for(int l = 1; l <= n; l ++)// On
//                 {
//                     if(a[l] % j)continue;
//                     mul[j] ++;
//                 }
//             }
//             if(mul[j] < k)continue;
//             ans[i] = max(ans[i], j);
//         }
//     }
//     for(int i = 1; i <= n; i ++)cout << (ans[i] ? ans[i] : 1) << endl;
// }
//
// signed main()
// {
//     ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
//     init();
//     return 0;
// }

#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;

const int N = 1.2 * 1e6 + 9;
int a[N], cnt[N], mul[N], ans[N];

inline void init()
{
    int n, k;cin >> n >> k;
    for(int i = 1; i <= n; i ++)cin >> a[i];
    int mx = *max_element(a + 1, a + 1 + n);

    // 计算每个因子的倍数出现的次数
    // for(int i = 1; i <= n; i ++)
    //     for(int j = 1; j <= a[i]; j ++)
    //         if(a[i] % j == 0)
    //             mul[j] ++;
    for(int i = 1; i <= n; i ++)// On
        cnt[a[i]] ++;
    for(int i = 1; i <= mx; i ++)// Om
        for(int j = i; j <= mx; j += i)// Ologm
            mul[i] += cnt[j];
    // 直接枚举所有可能因子
    for(int i = 1; i <= mx; i ++)// Om
    {
        // 若因子出现数<k,则continue
        // 需要统计数组中是因子倍数的个数
        if(mul[i] < k)continue;
        // 若可以是答案,就把因子的倍数更新
        for(int j = i; j <= mx; j += i)// Ologm
            ans[j] = max(ans[j], i);
    }
    for(int i = 1; i <= n; i ++)
        cout << ans[a[i]] << endl;
}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值