vp Codeforces Round 588 (Div. 2)

A - Dawid and Bags of Candies

题意:给你四个数,要你将他们平均分给两个人,看能不能平均分给两个人

思路:挺简单的,就先看他们的总和是不是偶数,不是肯定不行,是的话再进行判断,因为只有两种分配方式2和2,1和3,第一个种就选第一个数,看有没有数和他加起来等于总和的一半,第二个就是看有没有一个数等于总和的一半(刚开始没进入状态wa了好几发)

代码:

void solve() // 22 31
{
    int sum = 0;
    for (int i = 1; i <= 4; i++)
        cin >> a[i], sum += a[i];
    if (sum & 1)
    {
        cout << "NO" << endl;
        return;
    }
    for (int i = 2; i <= 4; i++)
    {
        if (a[1] + a[i] == sum / 2)
        {
            cout << "YES" << endl;
            return;
        }
    }
    for (int i = 1; i <= 4; i++)
        if (a[i] == sum / 2)
        {
            cout << "YES" << endl;
            return;
        }
    cout << "NO" << endl;
}

B - Ania and Minimizing

题意:给你一个长度为n的大整数(以字符串的形式),你最多可以对他进行k次操作,每次操作是你可以将他的任意一位换成0~9的任意数字,但是不能让他有前导0,请你输出让他最小的整数

思路:其实就是贪心,再特判只有一位的时候以及k等于0的时候,如果k不等于0,分两种情况,第一位是1的话,就向后看将他的非0的那一位进行操作最多k次,将他变成0,如果第一位不是1 ,就将第一位变成1,k--,再进行上述的操作即可

代码:

void solve() //
{
    int n, k;
    cin >> n >> k; // 尽量让小的数占据高位
    string s;
    cin >> s;
    if (k == 0)
    {
        cout << s << endl;
        return;
    }
    if (s.size() == 1)
    {
        cout << 0 << endl;
        return;
    }
    if (s[0] == '1')
    {
        for (int i = 1; i < s.size(); i++)
        {
            if (k == 0)
                break;
            if (s[i] != '0')
                s[i] = '0', k--;
        }
    }
    else
    {
        s[0] = '1';
        k--;
        for (int i = 1; i < s.size(); i++)
        {
            if (k == 0)
                break;
            if (s[i] != '0')
                s[i] = '0', k--;
        }
    }
    cout << s << endl;
}

C - Anadi and Domino

题意:给你n个点,m条边,然后要在边上插入一个多米诺骨牌(有两个部分,每个部分都有相应的点数),每个点被指向点数必须相同,要求你求出最多可以给多少条边加上多米诺骨牌

思路:数据挺小的,容易找规律发现,如果顶点小于等于6的话,直接让每个顶点的下标被指向相应的点数就行,所以直接输出m就行,再特判一下七个点0条边的情况,顶点数大于7的话说明肯定是有两个点是重合的,但是两个重合的点是不能存在多条边连到另外一个点的,所以只要找出这样的边的数量,再将其删去,其他的都可以按照上述的操作把所有的边都加上多米诺骨牌

代码:

void solve() // 在图上放多米诺骨牌,看最多可以放多少个,每个指向同一顶点的半部分上的点都得相同
{
    cin >> n >> m;
    int sum = 0;
    for (int i = 1; i <= m; i++)
    {
        cin >> a[i] >> b[i];
        flag[a[i]][b[i]] = flag[b[i]][a[i]] = 1;
        if (a[i] <= 6 && b[i] <= 6)
            sum++;
    }
    if (m == 0)
    {
        cout << 0 << endl;
        return;
    }
    if (n <= 6)
    {
        cout << m << endl;
        return; // 顶点数小于6,直接让顶点的标号作为指向它的点数即可
    }
    else // 多于6个点
    {    // 由于最多有6个顶点,如果出现了第7个顶点,那么就说明肯定有两个点是相同的,而这两相同的顶点是不能连同一条边的,所以可以直接记录有两个相同的点连同一条边的,让从m中删掉即可
        int cnt = 0x3f3f3f3f;
        for (int i = 1; i <= n; i++)
        {
            for (int j = i + 1; j <= n; j++) // 由于多出点肯定是和之前的某个点重合的,所以可以直接将j看做是和i重合的点
            {
                int res = 0;
                for (int k = 1; k <= n; k++)
                    if (flag[i][k] && flag[j][k])
                        res++; // 记录可以删除的边
                cnt = min(cnt, res);
            }
        }
        cout << m - cnt << endl;
    }
}

D - Marcin and Training Camp

题意:给你n个人会的算法值和他们的能力值,要你求出所有能组队的队伍的最大能力值,能组队的队伍指的就是队伍中有两个及其以上的人是最厉害的(也就是这个队伍中至少有两个人的算法值是最大的)(一个人x比另外一个人y厉害指的是:x&y==y)

思路:其实就是枚举即可,先预处理出每个算法值出现的次数,再枚举每个人当他所在组的父亲(算法值最大的),只有至少存在一个和他算法值相同的情况才,他才能作为组中最大的,再用一个数组标记他被某个组选中了的(防止重复算),再在处理后将原来的算法值出现次数处理就行

tips:==判断符号是比位运算的优先级要高的,这就说明,在没有括号的情况下,优先执行==,例如a[i]&a[j]==a[j]这个程序的执行是先执行a[j]==a[j]然后返回1,再让a[i]和1做按位与,正确的应该是(a[i]&a[j])==a[j]

代码:

#define int long long
const int N = 7e3 + 10; // 只有所知道的算法是完全相同的才能放到一组,再求他们的最大能值
struct node
{
    int a, b;
} ans[N];
int father[N];
int temp[N]; // 处理每个人可能组队的最大值
int n;       // 这个可以组队的意思是,一个组中只有一个人是最大的,那么这个组就不能成立,所以可以处理出每个人的最大最大组队的值,再全加起来
// 看一个数组确定某个人是否已经被某个人选中变成一组了
void solve() // 其实按照这个比较,一个人比另外一个人强大就是看他们进行与运算怎么样,a[i]&a[j]==a[j]说明a[i]比a[j]强大
{
    cin >> n;
    unordered_map<int, int> mp; // 记录出现的次数
    for (int i = 1; i <= n; i++)
        cin >> ans[i].a, mp[ans[i].a]++;
    for (int i = 1; i <= n; i++)
        cin >> ans[i].b;
    for (int i = 1; i <= n; i++)
    {
        int now = ans[i].a;
        if (mp[ans[i].a] < 2)
            continue; /// 如果这个数出现的次数小于2,说明如果和他组队找不到和他一样的(默认选取的这个数最大),直接跳过
        for (int j = 1; j <= n; j++)
            if ((father[j] == 0 || father[j] == i) && ((now & ans[j].a) == ans[j].a)) // 如果这个数还没有进入某个人的组,或者已经是这个组的了,同时他要比他的父亲小,才能加到这个组中
                father[j] = i, temp[i] += ans[j].b;                                   // 把这个数加到这个组中,就是将他的父节点标记
        mp[ans[i].a] = -1;                                                            // 说明这个数已经被选做一次父亲了,所以防止重复,归零
    }
    int sum = 0;
    for (int i = 1; i <= n; i++)
        sum += temp[i]; // 加上选每个数为父节点所能组成的组的最大值即可
    cout << sum << endl;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值