Codeforces Round #721 (Div. 2)

本文介绍了两个与位运算和回文串相关的博弈问题。第一题涉及位运算,讨论了如何找到最大的k使得特定位运算后的结果为0,关键在于分析二进制表示。第二题是关于回文串的博弈策略,分为容易和困难两种情况,分析了先手和后手的胜利条件。最后,第三题讨论了序列对权重的计算,关注相同元素在不同位置的组合对总和的影响。文章通过实例解析和代码展示了解决这些问题的方法。

A And Then There Were K

题目大意

给一个n,求最大的k满足
n & (n−1) & (n−2) & (n−3) & … (k) = 0

主要思路

当n的二进制位数-1时必然会经过1xxxx -> 10000 这时把前面的数都&起来,由于第一位1无法消除,所以最大的数一定是10000 - 1是第一个能把n的第一位1消除的,所以答案就为n的二进制位的个数减1个1组成的数

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <string>
#include <cmath>
#include <unordered_map>
using namespace std;

#define int long long
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef pair<int, int> P;

signed main(void)
{
    int T;
    cin >> T;
    while(T--)
    {
        int n;
        cin >> n;
        int res = 0;
        while(n)
        {
            res <<= 1;
            res++;
            n >>= 1;
        }
        res >>= 1;
        cout << res << endl;
    }
    return 0;
}

B1 Palindrome Game (easy version)

题目大意

给一个回文串,先手和后手有两种操作:

  1. 把一个0,变成一个1,花费1的代价
  2. 如果前一次操作不是2操作并且当前串不是个回文串,把当前串反转,不花费代价

ALICE先手,BOB后手

主要思路

由于是回文串,ALICE先手只能把0变为1。

  • 考虑0的个数为偶数时,BOB的最优操作是在对称位置将0变成1,在仅有2个0的时候,还是回文串ALICE只能把0变为1,此时BOB翻转字符串,下次操作ALICE不能翻转,那么BOB必胜
  • 考虑0的个数为奇数时,那么ALICE先手把中间的0变为1,此时相当于BOB先手,ALICE必胜

考虑特殊情况

  • 当场上仅有1个0时,BOB必胜
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <string>
#include <cmath>
#include <unordered_map>
using namespace std;

#define int long long
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef pair<int, int> P;

signed main(void)
{
    int T;
    cin >> T;
    while(T--)
    {
        int n;
        cin >> n;
        string t;
        cin >> t;
        int cnt0 = 0;
        for(int i = 0; i < t.size(); i++)
        {
            if(t[i] == '0') cnt0++;
        }
        
        if(cnt0 == 0) puts("DRAW");
        else if(cnt0 % 2 == 0 || cnt0 == 1) puts("BOB");
        else puts("ALICE");
    }
    return 0;
}

B2 Palindrome Game (hard version)

题目大意

跟上题相同,不过给的串不一定是回文串

主要思路
  • 回文串情况与上题相同,接下来仅考虑不是回文串情况

  • 由于不是回文串,ALICE开局翻转即可,那么BOB的最佳操作就必须将0改为1,且向回文串靠近,这样ALICE才能不翻转,但在BOB将串改为回文串之前,ALICE可以讲串提前改为回文串,那么BOB必须修改(ALICE真的太坏了),ALICE必胜。

考虑特殊情况

  • 当开局场上仅有两个0且将一个0变为1就能修改为回文串时,必平局
    • ALICE修改为回文串,BOB也必须修改
    • ALICE翻转,BOB修改为回文串,ALICE修改
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <string>
#include <unordered_map>
#include <set>
#include <queue>
using namespace std;

#define int long long
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef pair<int, int> P;


signed main(void)
{
    ios::sync_with_stdio(false);
    int T;
    cin >> T;
    while(T--)
    {
        int n;
        cin >> n;
        string t;
        cin >> t;
        bool flag = true;
        int cnt0 = 0;
        for(int i = 0; i < t.size(); i++)
        {
            if(t[i] != t[t.size() - 1 - i]) flag = false;
            if(t[i] == '0') cnt0++;
        }

        if(flag)
        {
            if(cnt0 == 0) puts("DRAW");
            else if(cnt0 % 2 == 0 || cnt0 == 1) puts("BOB");
            else puts("ALICE");
        }
        else
        {
            if(cnt0 == 2 && t[t.size() / 2] == '0' && t.size() % 2) puts("DRAW");
            else puts("ALICE");
        }
    }
    return 0;
}

C Sequence Pair Weight

题目大意

定义sum为一个数列中相同的数在不同位置的对数,问对于一个数列,它的串及其所有子串的sum和为多少

主要思路

经典套路!

我们先考虑一个数对对答案的贡献。

假设a1, a2, a3, …, ai, 中a3与ai相同,那么这个数对对答案的贡献首先a3可以向前拓展2个位置,ai可以向后拓展到n位置,也就是字串除必须有a3~ai外,a3也可以为,a2,a3或者a1,a2,a3一共3种情况,ai向后拓展同理,所以这个数对对答案的贡献为3 * (n - i + 1)。

接下来考虑多个数对情况

假设a1, a2, a3, …, ai,中a1,a3与ai相同,那么ai可以与前两个数凑成数对,也就是(1 + 3) * (n - i + 1),所以我们只需要维护前i个数中,a[i]的下标和即可

如果求所有的数的贡献,只要记录相同数出现的下标之和,每次结果加上 (当前数出现过的下标之和)*(n-i+1)

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <string>
#include <cmath>
#include <unordered_map>
#include <queue>
using namespace std;

#define int long long
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef pair<int, int> P;

const int N = 100010;
int n, a[N];

signed main(void)
{
    std::ios::sync_with_stdio(false);
    unordered_map<int, int> mp;
    int T;
    cin >> T;
    while(T--)
    {
        mp.clear();
        int res = 0;
        int n;
        cin >> n;
        for(int i = 1; i <= n; i++)
        {
            cin >> a[i];
            res += mp[a[i]] * (n - i + 1);
            mp[a[i]] += i;
        }
        cout << res << endl;
    }
    return 0;
}
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值