Codeforces Round # 721 (Div. 2)

本文介绍了三位数位运算的博弈问题,包括找到最大值使得连续按位与结果为零,以及两种博弈策略:回文串构造和序列配对权重。解题思路涉及位运算性质、回文串特性以及动态规划思想,展示了如何通过位运算优化算法复杂度。
摘要由CSDN通过智能技术生成

Codeforces Round # 721 (Div. 2)

2021/05/20

https://codeforces.com/contest/1527

A. And Then There Were K

time limit per test : 1 second
memory limit per test : 256 megabytes
input : standard input
output : standard output

题目描述

Given an integer n, find the maximum value of integer k such that the following condition holds:

n & (n−1) & (n−2) & (n−3) & … (k) = 0

where & denotes the bitwise AND operation.

Input

The first line contains a single integer t (1≤t≤3⋅104). Then t test cases follow.

The first line of each test case contains a single integer n (1≤n≤109).

Output

For each test case, output a single integer — the required integer k.

Examples
input
3
2
5
17
output
1
3
15
Note

In the first testcase, the maximum value for which the continuous & operation gives 0 value, is 1.

In the second testcase, the maximum value for which the continuous & operation gives 0 value, is 3. No value greater then 3, say for example 4, will give the & sum 0.

  • 5&4≠0,
  • 5&4&3=0.

Hence, 3 is the answer.

解题思路

对于这个数我跟把他换成二进制,假设它的每一位是x1x2x3…xn
那进行&操作后要想结果为零那么必然每一位都得出现一次0,首先x1肯定不是0(不然就没有这一位了),要想使这一位为0,那必须要&的最大数为0(11…11)n-1个那在这个数之前必然经历了1(00…00)n-1个,因为他是从原数本身减下来的嘛。这样就能使最终结果为0了。所以答案就是0(11…11)n-1个

AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <string>
#include <cmath>

/* Author Information
 * Author: 六月陌
 * Time: 2021-05-20 22:35:04
**/


#define max(a,b) ((a>b)?(a):(b))
#define min(a,b) ((a<b)?(a):(b))
#define ll long long
#define endl "\n"
#define lowbit(x) ((x)&(-x))

using namespace std;
const int maxn=1e5+10;
const int mod = 1e9+7;
template<typename T>
T gcd(T a,T b)
{
    while(b^=a^=b^=a%=b);
    return a;
}
int t,n;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        int temp = 0;
        while(n>1)
        {
            temp++;
            n>>=1;
        }
        n<<=temp;
        n--;
        printf("%d\n",n);
    }
    return 0;
}

 
 

B1. Palindrome Game (easy version)

time limit per test : 1 second
memory limit per test : 256 megabytes
input : standard input
output : standard output

题目描述

The only difference between the easy and hard versions is that the given string s in the easy version is initially a palindrome, this condition is not always true for the hard version.

A palindrome is a string that reads the same left to right and right to left. For example, “101101” is a palindrome, while “0101” is not.

Alice and Bob are playing a game on a string s (which is initially a palindrome in this version) of length n consisting of the characters ‘0’ and ‘1’. Both players take alternate turns with Alice going first.

In each turn, the player can perform one of the following operations:

  • 1.Choose any i (1≤i≤n), where s[i]= ‘0’ and change s[i] to ‘1’. Pay 1 dollar.
  • 2.Reverse the whole string, pay 0 dollars. This operation is only allowed if the string is currently not a palindrome, and the last operation was not reverse. That is, if Alice reverses the string, then Bob can’t reverse in the next move, and vice versa.

Reversing a string means reordering its letters from the last to the first. For example, “01001” becomes “10010” after reversing.

The game ends when every character of string becomes ‘1’. The player who spends minimum dollars till this point wins the game and it is a draw if both spend equal dollars. If both players play optimally, output whether Alice wins, Bob wins, or if it is a draw.

Input

The first line contains a single integer t (1≤t≤103). Then t test cases follow.

The first line of each test case contains a single integer n (1≤n≤103).

The second line of each test case contains the string s of length n, consisting of the characters ‘0’ and ‘1’. It is guaranteed that the string s is a palindrome and contains at least one ‘0’.

Note that there is no limit on the sum of n over test cases.

Output

For each test case print a single word in a new line:

  • “ALICE”, if Alice will win the game,
  • “BOB”, if Bob will win the game,
  • “DRAW”, if the game ends in a draw.
Examples
input
2
4
1001
1
0
output
BOB
BOB
Note

In the first test case of the example,

  • in the 1-st move Alice has to perform the 1-st operation, since the string is currently a palindrome.
  • in the 2-nd move Bob reverses the string.
  • in the 3-rd move Alice again has to perform the 1-st operation. All

characters of the string are ‘1’, game over.
Alice spends 2 dollars while Bob spends 0 dollars. Hence, Bob always wins.

解题思路

首先在这个简易版本中给定的字符串肯定是回文串,那这样就好办了。
首要要明白一点,在回文串中如果出现了奇数个0,那最中间位置一定是0,因为是对称的嘛,a[i] == a[n-i+1] 所以只有当i = n-i+1的时候才能出现不配对的单个0;

  • 若给出的字符串中只有一个0,BOB肯定赢,(回文串0在中间,ALICE不能反转,只能花钱改1)ALICE比BOB多花1美元
  • 若给出的字符串中不止一个0,且0的个数为奇数个,那中间一定有0 ,假定为100101001,她只要不选中间的0,那BOB就一定能反转,ALICE必输,所以她只能尽力创造回文串,让BOB不能反转,之后BOB每选一个,ALICE就选和他对称的,让字符串一直是回文串,这样BOB就不能反转了,直到最后只剩一个0的时候,ALICE反转一下就赢了。所以大于一个0,且为奇数时,ALICE必胜。这样BOB比ALICE多花1美元
  • 偶数个0时跟刚刚一样,无论ALICE选哪个,BOB都选和她对称的,直到最后一个的时候反转一下ALICE必输,没有翻盘的机会。 这样ALICE比BOB多花两美元

总结一下:就是0的个数为奇数且大于1的时候ALICE才能必赢,不然必输,只要会玩根本不存在平局。

AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <string>
#include <cmath>

/* Author Information
 * Author: 六月陌
 * Time: 2021-05-20 22:35:04
**/


#define max(a,b) ((a>b)?(a):(b))
#define min(a,b) ((a<b)?(a):(b))
#define ll long long
#define endl "\n"
#define lowbit(x) ((x)&(-x))

using namespace std;
const int maxn=1e3+10;
const int mod = 1e9+7;

int t,n;
char s[maxn];
int main()
{

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        getchar();
        for(int i=0;i<n;i++) scanf("%c",&s[i]);
        int count = 0;
        bool flag = true;
        for(int i=0;i<n;i++)
        {
            if(s[i] == '0') count++;
        }
        if(count % 2 == 1 && count > 1) 
        {
            printf("ALICE\n");
        }else
        {
            printf("BOB\n");
        }
    }

    return 0;
}

 
 

B2. Palindrome Game (hard version)

time limit per test : 1 second
memory limit per test : 256 megabytes
input : standard input
output : standard output

题目描述

The only difference between the easy and hard versions is that the given string s in the easy version is initially a palindrome, this condition is not always true for the hard version.

A palindrome is a string that reads the same left to right and right to left. For example, “101101” is a palindrome, while “0101” is not.

Alice and Bob are playing a game on a string s of length n consisting of the characters ‘0’ and ‘1’. Both players take alternate turns with Alice going first.

In each turn, the player can perform one of the following operations:

Choose any i (1≤i≤n), where s[i]= ‘0’ and change s[i] to ‘1’. Pay 1 dollar.
Reverse the whole string, pay 0 dollars. This operation is only allowed if the string is currently not a palindrome, and the last operation was not reverse. That is, if Alice reverses the string, then Bob can’t reverse in the next move, and vice versa.
Reversing a string means reordering its letters from the last to the first. For example, “01001” becomes “10010” after reversing.

The game ends when every character of string becomes ‘1’. The player who spends minimum dollars till this point wins the game and it is a draw if both spend equal dollars. If both players play optimally, output whether Alice wins, Bob wins, or if it is a draw.

Input

The first line contains a single integer t (1≤t≤103). Then t test cases follow.

The first line of each test case contains a single integer n (1≤n≤103).

The second line of each test case contains the string s of length n, consisting of the characters ‘0’ and ‘1’. It is guaranteed that the string s contains at least one ‘0’.

Note that there is no limit on the sum of n over test cases.

Output

For each test case print a single word in a new line:

  • “ALICE”, if Alice will win the game,
  • “BOB”, if Bob will win the game,
  • “DRAW”, if the game ends in a draw.
Examples
input
3
3
110
2
00
4
1010
output
ALICE
BOB
ALICE
Note

In the first test case of example,

  • in the 1-st move, Alice will use the 2-nd operation to reverse the string, since doing the 1-st operation will result in her loss anyway. This also forces Bob to use the 1-st operation.
  • in the 2-nd move, Bob has to perform the 1-st operation, since the 2-nd operation cannot be performed twice in a row. All characters of the string are ‘1’, game over.

Alice spends 0 dollars while Bob spends 1 dollar. Hence, Alice wins.
In the second test case of example,

  • in the 1-st move Alice has to perform the 1-st operation, since the string is currently a palindrome.
  • in the 2-nd move Bob reverses the string.
  • in the 3-rd move Alice again has to perform the 1-st operation. All

characters of the string are ‘1’, game over.
Alice spends 2 dollars while Bob spends 0 dollars. Hence, Bob wins.

解题思路

简易版本不是白给的,肯定是给我们提供思路,我们一定要用到简易版本。
既然简易版本一定分析了回文串的情况,那我们就直接用。然后分析不是回文串的情况。
如果一开始不是回文串那ALICE就能反转,只要一直不是回文串就一直反转,转下去BOB一点办法都没有,所以BOB一定要凑出回文串才有翻盘的希望。

  • 如果只有一个0,那ALICE反转一下,BOB就输了
  • 在简易版本中我们知道花费最多只会差2美元,所以BOB如果两次都不能凑出回文那他就必输了,因为你凑回文后相当于ALICE初始花费-2美元,然后先手嘛。
  • 如果BOB两次就能凑回文,那BOB操作第一次后ALICE可以抢第二次去凑回文,那BOB就没机会了,因为现在两人各花费1美元但BOB先手,所以BOB输。
  • 如果一次就能凑出回文,那ALICE肯定要去凑回文,那这样如果只有两个0,一人选一个就平局了,否则还是BOB输。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <string>
#include <cmath>

/* Author Information
 * Author: 六月陌
 * Time: 2021-05-20 22:35:04
**/


#define max(a,b) ((a>b)?(a):(b))
#define min(a,b) ((a<b)?(a):(b))
#define ll long long
#define endl "\n"
#define lowbit(x) ((x)&(-x))

using namespace std;
const int maxn=1e3+10;
const int mod = 1e9+7;

int t,n;
char s[maxn];
int main()
{

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        getchar();
        for(int i=0;i<n;i++) scanf("%c",&s[i]);
        int count = 0;
        int temp = 0;
        bool flag = true;
        for(int i=0;i<n;i++)
        {
            if(s[i] == '0') count++;
            if(s[i] != s[n-1-i])
            {
                flag = false;
                temp++;
            }  
        }
        temp /= 2;
        if(flag)
        {
            if(count % 2 == 1 && count > 1) 
            {
                printf("ALICE\n");
            }else
            {
                printf("BOB\n");
            }
        }else
        {
            if(count == 2 && temp == 1) printf("DRAW\n");
            else printf("ALICE\n");
        }
    }

    return 0;
}

 
 

C. Sequence Pair Weight

time limit per test : 2 second
memory limit per test : 256 megabytes
input : standard input
output : standard output

题目描述

The weight of a sequence is defined as the number of unordered pairs of indexes (i,j) (here i<j) with same value (ai=aj). For example, the weight of sequence a=[1,1,2,2,1] is 4. The set of unordered pairs of indexes with same value are (1,2), (1,5), (2,5), and (3,4).

You are given a sequence a of n integers. Print the sum of the weight of all subsegments of a.

A sequence b is a subsegment of a sequence a if b can be obtained from a by deletion of several (possibly, zero or all) elements from the beginning and several (possibly, zero or all) elements from the end.

Input

Each test contains multiple test cases. The first line contains the number of test cases t (1≤t≤105). Description of the test cases follows.

The first line of each test case contains a single integer n (1≤n≤105).

The second line of each test case contains n integers a1,a2,…,an (1≤ai≤109).

It is guaranteed that the sum of n over all test cases does not exceed 105.

Output

For each test case, print a single integer — the sum of the weight of all subsegments of a.

Examples
input
2
4
1 2 1 1
4
1 2 3 4
output
6
0
Note
  • In test case 1, all possible subsegments of sequence [1,2,1,1] having size more than 1 are:
          [1,2] having 0 valid unordered pairs;
          [2,1] having 0 valid unordered pairs;
          [1,1] having 1 valid unordered pair;
          [1,2,1] having 1 valid unordered pairs;
          [2,1,1] having 1 valid unordered pair;
          [1,2,1,1] having 3 valid unordered pairs.
    Answer is 6.
  • In test case 2, all elements of the sequence are distinct. So, there is no valid unordered pair with the same value for any subarray. Answer is 0.
解题思路

我们转换一下思路,找每个区间有多少对,跟找每对会出现与多少个区间是一个道理吧。
比如简单点的例子 1 1 2 3 4,这里面只有1和1凑成一对,一共有很多个区间但只有区间(1,2)(1,3)(1,4)(1,5)里面能凑出两个1,就相当于这一对1出现在了这4个区间。
拿好了我们分析这个题,在a1,a2 … an中,任意的ai = aj (i<j) 能出现在几个区间呢?首先(i,j)是一个吧(i-1,j)又是一个吧,(i,j+1)也是一个吧(i-1,j+1)也是一个,是不是一共就有 i * (n-j+1)个,i及其左边的元素个数乘以j及其右边的元素个数。那我们把每一对的区间总数相加就行了啊。
但这样是O(n2)的算法,还是超时,我们再简化,对于区间(i,j),我们把右端点固定,加入 现在 a1 = a3 = ai,那从a1到ai加起来的是什么呢?对于a1: 1 * (n-j+1) 对于 a3 : 3 * (n-j+1),对于ai : i * (n-j+1)
那这些加起来就是(1 + 3 + i) * (n-j+1),对于其他的区间(i,x) 加起来是不是就是(1 + 3 + i) * (n-x+1) 对于 (i,y) 是不是 (1 + 3 + i) * (n-y+1),所以前面的这些是固定的,我们可以用一个map来保存前面1 + 3 + i,然后只遍历j就行了,这样算法是O(nlogn)的。

AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <string>
#include <cmath>

/* Author Information
 * Author: 六月陌
 * Time: 2021-05-20 22:35:04
**/


#define max(a,b) ((a>b)?(a):(b))
#define min(a,b) ((a<b)?(a):(b))
#define ll long long
#define endl "\n"
#define lowbit(x) ((x)&(-x))

using namespace std;
const int maxn=1e5+10;
const int mod = 1e9+7;
template<typename T>
T gcd(T a,T b)
{
    while(b^=a^=b^=a%=b);
    return a;
}
long long C(int temp)
{
    return (temp*(temp-1))>>1;
}
int t,n;
int a[maxn];
map<int,long long> mp;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        long long ans = 0;
        mp.clear();
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
        }
        for(int i=0;i<n;i++)
        {
            ans += mp[a[i]] * (n-i);
            mp[a[i]] += i+1;
        }
        printf("%lld\n",ans);
    }

    return 0;
}

 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值