Codeforces Round #748 (Div. 3)

这篇博客介绍了如何通过计算三名候选人的选票差距,找出各自需要增加的最低选票数量,以便超过其他两位对手。涉及的编程技巧包括判断最大差值和贪心算法应用。

A Elections

题目大意

给定三个人的选票数,问每个人需要加多少张选票才能超过其他两个人

主要思路

判断与其他两人差的选票的最大值即可,因为当前可能是选票最多的人所以与0取max即可

AC代码
#include <iostream>
#include <queue>
#include <algorithm>
 
#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 100010, mod = 998244353;
 
int n, m, a[N];
 
signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
 
    int T;
    cin >> T;
    while(T--)
    {
        int a, b, c;
        cin >> a >> b >> c;
        cout << max((int)0, max(b - a, c - a) + 1) << ' ' << max((int)0, max(a - b, c - b) + 1) << ' ' << max((int)0, max(a - c, b - c) + 1) << endl;
    }
    return 0;
}

B Make it Divisible by 25

题目大意

给定一个数字,问最少去掉几个数让该数是25的倍数

主要思路

由于25的倍数最后两位只能是00,25, 50, 75,所以暴力枚举最后两位的值,取应去掉的个数最小值即可

AC代码
#include <iostream>
#include <queue>
#include <algorithm>
 
#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 100010, mod = 998244353;
 
int n, m, a[N];
 
signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
 
    int T;
    cin >> T;
    while(T--)
    {
        string s;
        cin >> s;
        int ans = 1e9;
        for(int i = 0; i < s.size(); i++)
        {
            for(int j = i + 1; j < s.size(); j++)
            {
                int now = (s[i] - '0') * 10 + s[j] - '0';
                if(now % 25 == 0)
                {
                    ans = min(ans, (int)s.size() - i - 2);//答案至于靠前的一位的位置有关,需要从s的末尾到i除了i,j位置全部删除
                }
            }
        }
        cout << ans << endl;
    }
    return 0;
}

C Save More Mice

题目大意

0位置有一只猫,n位置有老鼠洞,每次任选一直老鼠向右移动1个位置,然后猫向右移动一个位置,如果猫所在格子有老鼠,猫会把他们全部抓住,问最多存活多少老鼠(走到老鼠洞既存活)

主要思路

贪心,每次先让离得最近的老鼠先进洞,因为猫走n步就能走到老鼠洞,所以所有老鼠也最多走n步。

AC代码
#include <bits/stdc++.h>
 
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 400010, mod = 998244353;
 
int n, m;
 
bool cmp(int a, int b)
{
    return a > b;
}
 
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
 
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n >> m;
        vector<int> a(m + 1);
        for(int i = 0; i < m; i++) cin >> a[i];
        sort(a.begin(), a.end(), cmp);

        int cnt = 0;
        int ori = n;//所有老鼠最多走n位置
        for (int i = 0; i < m; i ++ )
        {
            if (ori >= n - a[i] && n - ori < a[i])//还有多余的步数并且大于猫的位置
            {
                cnt ++ ;
                ori -= n - a[i];
            }
            else break;
        }
        cout << cnt << endl;
    }
    return 0;
}

D1 All are Same

题目大意

给定n个数,每次让任意数减小k,不限次数,最后让所有数相等,问k的最大值

主要思路

先找到数组中的最小值,然后取所有与最小值差的gcd即可

AC代码
#include <bits/stdc++.h>
 
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 400010, mod = 998244353;
 
int n, m, a[110];
 
int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}
 
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
 
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
        int mn = 1e9;
        for(int i = 0; i < n; i++)
        {
            cin >> a[i];
            mn = min(mn, a[i]);
        }

        int ans = 0;
        for(int i = 0; i < n; i++)
        {
            if(a[i] == mn) continue;
            ans = gcd(ans, a[i] - mn);
        }
        if(ans == 0) ans = -1;
        cout << ans << endl;
    }
    return 0;
}

D2 Half of Same

题目大意

与D1大意相同,不过只要求有一半数相等即可

主要思路

借鉴这位聚聚的思路:https://www.bilibili.com/read/cv13582275

首先枚举任意两个数的差,那么答案k一定存在在差的因数中,所以枚举每组差的因数,判断当前k是否满足,取满足的最大值即可

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 110, mod = 998244353;

int n, a[N];

int update(int d, int x)
{
    int ans = 0;
    for(int i = 1; i * i <= d; i++)//枚举因数
    {
        if(d % i) continue;
        int cnt = 0;
        for(int j = 0; j < n; j++)
        {
            if(abs(a[j] - x) % i == 0) cnt++;
        }
        if(cnt >= (n + 1) / 2) ans = max(ans, i);
        
        cnt = 0;
        for(int j = 0; j < n; j++)
        {
            if(abs(a[j] - x) % (d / i) == 0) cnt++;
        }
        if(cnt >= (n + 1) / 2) ans = max(ans, d / i);
    }
    
    return ans;
}

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int T;
    cin >> T;
    while(T--)
    {
        map<int, int> mp;
        cin >> n;
        for(int i = 0; i < n; i++) cin >> a[i], mp[a[i]]++;
        
        bool flag = false;
        for(auto i : mp)
        {
            if(i.y >= (n + 1) / 2) flag = true;
        }
        if(flag)
        {
            cout << -1 << endl;
            continue;
        }
        
        int ans = -1;
        for(int i = 0; i < n; i++)
        {
            for(int j = i + 1; j < n; j++)
            {
                int d = abs(a[i] - a[j]);//枚举差
                if(!d) continue;
                ans = max(ans, update(d, a[i]));
                //debug(d)debug(ans)
            }
        }
        cout << ans << endl;
    }
    return 0;
}

E Gardener and Tree

题目大意

给定一个树,每次去掉叶子节点,问经过k次操作后,还剩多少节点

主要思路

输入时存每个点的入度和出度,然后把度小于等于1的放进队列同时记位第一层,然后从队头开始弹出元素,枚举当前点的临边,假设枚举到的临边的度-1后等于1,那么说明他是下一层的点,更新层数以及加入队列,最后枚举每个点的层数是否大于k即可

AC代码
#include <iostream>
#include <queue>
#include <algorithm>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 400010, mod = 998244353;

int n, m, d[N], st[N];
int h[N], e[N * 2], ne[N * 2], idx;

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void init()
{
    idx = 0;
    for(int i = 1; i <= n; i++)
    {
        st[i] = 0, d[i] = 0, h[i] = -1;
    }
}

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int T;
    cin >> T;
    while(T--)
    {
        cin >> n >> m;
        init();
        for(int i = 0; i < n - 1; i++)
        {
            int a, b;
            cin >> a >> b;
            add(a, b), add(b, a);
            d[a]++, d[b]++;
        }
        queue<int> q;
        
        for(int i = 1; i <= n; i++)
        {
            if(d[i] <= 1)
            {
                st[i] = 1;
                q.push(i);
            }
        }
        while(q.size())
        {
            int t = q.front(); q.pop();
            
            for(int i = h[t]; ~i; i = ne[i])
            {
                int j = e[i];
                if(--d[j] == 1)
                {
                    st[j] = st[t] + 1;
                    q.push(j);
                }
            }
        }
        int res = 0;
        for(int i = 1; i <= n; i++) if(st[i] > m) res++;
        cout << res << endl;
    }
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值