Codeforces Round #717 (Div.2 )
2021/04/21
A. Tit for Tat
题目描述
Given an array a of length n, you can do at most k operations of the following type on it:
- choose 2 different elements in the array, add 1 to the first, and subtract 1 from the second. However, all the elements of a have to remain non-negative after this operation.
What is lexicographically the smallest array you can obtain?
An array x is lexicographically smaller than an array y if there exists an index i such that xi<yi, and xi=yi for all 1≤j<i. Less formally, at the first index i in which they differ,xi<yi.
Input
The first line contains an integer t (1≤t≤20) – the number of test cases you need to solve.
The first line of each test case contains 2 integers n and k (2≤n≤100, 1≤k≤10000) — the number of elements in the array and the maximum number of operations you can make.
The second line contains n space-separated integers a1, a2, …, an (0≤ai≤100) — the elements of the array a.
Output
For each test case, print the lexicographically smallest array you can obtain after at most k operations.
Examples
input
2
3 1
3 1 4
2 10
1 0
output
2 1 5
0 1
Note
In the second test case, we start by subtracting 1 from the first element and adding 1 to the second. Then, we can’t get any lexicographically smaller arrays, because we can’t make any of the elements negative.
解题思路
根据题目定义两个数组第一个不一样的位置小说明数组小,比如:
2 4 6 7 3
3 1 1 1 1
因为第一个不一样的位置是第一位,而第一个的数组的第一位小于第二个,所以第一个数组小。明白了这个就了然于心了,只要让前面的元素尽可能地小就行了,从第一个元素开始挨个往下减到0,最后一个元素往上加,直到k为0就行。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <string>
#include <cmath>
/* Author Information
* Author: 六月陌
* Time: 2021-04-21 21:35:05
**/
#define max(a,b) ((a>b)?(a):(b))
#define min(a,b) ((a<b)?(a):(b))
#define ll long long
#define endl "\n"
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,k;
int a[110];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>n>>k;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
for(int i=0;i<n-1&&k>0;i++)
{
if(a[i] <= k)
{
a[n-1] += a[i];
k -= a[i];
a[i] = 0;
}else
{
a[i] -= k;
a[n-1] += k;
k = 0;
}
}
bool flag = false;
for(int i=0;i<n;i++)
{
if(flag) cout<<" ";
cout<<a[i];
flag = true;
}
cout<<endl;
}
return 0;
}
B. AGAGA XOOORRR
题目描述
Baby Ehab is known for his love for a certain operation. He has an array a of length n, and he decided to keep doing the following operation on it:
- he picks 2 adjacent elements; he then removes them and places a single integer in their place: their bitwise XOR. Note that the length of the array decreases by one.
Now he asks you if he can make all elements of the array equal. Since babies like to make your life harder, he requires that you leave at least 2 elements remaining.
Input
The first line contains an integer t (1≤t≤15) — the number of test cases you need to solve.
The first line of each test case contains an integers n (2≤n≤2000) — the number of elements in the array a.
The second line contains n space-separated integers a1, a2, …, an (0≤ai<230) — the elements of the array a.
Output
If Baby Ehab can make all elements equal while leaving at least 2 elements standing, print “YES”. Otherwise, print “NO”.
Examples
input
2
3
0 2 2
4
2 3 1 10
output
YES
NO
Note
In the first sample, he can remove the first 2 elements, 0 and 2, and replace them by 0⊕2=2. The array will be [2,2], so all the elements are equal.
In the second sample, there’s no way to make all the elements equal.
解题思路
关于异或有两个性质
- a ^ a = 0
- 0 ^ a = a
如果我们最后得到了所有元素都相同的一个数组那么这个数组元素个数只可能有两种情况:1、个数为奇数 2、个数为偶数
如果个数是偶数那么最后异或的结果为0(两两异或得到0,最后一堆0异或还是0),如果个数为奇数那么两两异或得到一堆0和一个数。
我们判断所有数异或的结果,如果是0就输出YES,否则最后会得到一个数x,我们再扫一边数组,连着异或得到x就重新开始,直到扫完整个数组,如果最后的结果是0,且得到的x个数大于一就输出YES,否则输出NO
比如:
a1 a2 a3 a4 a5 a6 a7 a8 a9
所有元素异或完为x;
假设a1 ^ a2 ^ a3 = x
a4 ^ a5 ^ a6 ^ a7 = x
此时a8 != x 判断 a8 ^ a9是不是x就行了
如果只有a1 ^ a2 ^ a3 ^ a4 ^ a5 ^ a6 ^a7 ^ a8 ^a9 = x 这时只有一个元素,也是不行的。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <string>
#include <cmath>
/* Author Information
* Author: 六月陌
* Time: 2021-04-21 21:35:05
**/
#define max(a,b) ((a>b)?(a):(b))
#define min(a,b) ((a<b)?(a):(b))
#define ll long long
#define endl "\n"
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 a[2100];
set<int> st;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
int ans = 0;
for(int i=0;i<n;i++)
{
ans = ans^a[i];
}
if(ans == 0)
{
cout<<"YES\n";
}else
{
int temp = 0;
int count = 0;
for(int i=0;i<n;i++)
{
temp = temp^a[i];
if(temp == ans)
{
count++;
temp = 0;
}
}
if(temp == 0 && count >1) cout<<"YES\n";
else cout<<"NO\n";
}
}
return 0;
}
C. Baby Ehab Partitions Again
题目描述
Baby Ehab was toying around with arrays. He has an array a of length n. He defines an array to be good if there’s no way to partition it into 2 subsequences such that the sum of the elements in the first is equal to the sum of the elements in the second. Now he wants to remove the minimum number of elements in a so that it becomes a good array. Can you help him?
A sequence b is a subsequence of an array a if b can be obtained from a by deleting some (possibly zero or all) elements. A partitioning of an array is a way to divide it into 2 subsequences such that every element belongs to exactly one subsequence, so you must use all the elements, and you can’t share any elements.
Input
The first line contains an integer n (2≤n≤100) — the length of the array a.
The second line contains n integers a1, a2, …, an (1≤ai≤2000) — the elements of the array a.
Output
The first line should contain the minimum number of elements you need to remove.
The second line should contain the indices of the elements you’re removing, separated by spaces.
We can show that an answer always exists. If there are multiple solutions, you can print any.
Examples
input
4
6 3 9 12
output
1
2
input
2
1 2
output
0
Note
In the first example, you can partition the array into [6,9] and [3,12], so you must remove at least 1 element. Removing 3 is sufficient.
In the second example, the array is already good, so you don’t need to remove any elements.
解题思路
这题最容易想到的就是如果所有元素之和为奇数就一定不能分为两组。
如果所有元素之和为偶数就得判断一下,假设元素之和为sum(偶数)
可以通过dp来判断一下能不能从n个元素中凑出num/2
为了方便判断可以先将数组从小到大排序
dp[i][j]表示 可以从i个元素中凑出和为j的情况
显然dp[i][j] = dp[i-1][j] | dp[i-1][j-a[i]]
就是加不加最后一个元素的意思,如果不加最后一个元素,那么需要从前i-1个里凑出j,如果加上最后一个元素,则需要从i-1个里凑出j-a[i] (a[i]为最后一个元素)
为了节省点空间,可以将dp设为bool类型的,毕竟要开的数组挺大的
这样dp[n][sum/2] 为true就说明能分为两部分
能分就要删除元素,不能分就输出0
我们把所有数字考虑成二进制,发现
10+10 =100
10 + 11 = 101
10+ 100 = 110
10 + 101 = 111
发现没有,只有加数中的最低位有1的时候结果最低为才会出现1
比如要想让倒数第二位出现1,加数中倒数第二位要有1,或者加数中最后一个能进位这样倒数第二位才能出现1.
那如果不能进位呢?是不是这个位置就不能通过别的途径来代替了
我们可以通过求lowbit最小的元素将这个删掉就一定不能再分为两组了。
比如有个元素6二进制110,他的假设他的lowbit是最低的也就是说所有元素的lowbit最小是(10)2 这样就不可能出现1+1=10的情况了,不然lowbit就是1了。这样这个10的作用就是无可替代的。假设原来的数组分为了两组,总和都是xxxxx10
那么去掉6后有一组就回变为xxxxy00,而另一组为xxxxx10,你无法将倒数第二位变成一样的,也就不可能再等分为两组
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <string>
#include <cmath>
/* Author Information
* Author: 六月陌
* Time: 2021-04-21 21:35:05
**/
#define max(a,b) ((a>b)?(a):(b))
#define min(a,b) ((a<b)?(a):(b))
#define ll long long
#define endl "\n"
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 n;
struct num
{
int data;
int index;
}a[210];
bool dp[110][100010];
bool cmp(num a,num b)
{
return a.data<b.data;
}
int lowbit(int x)
{
return x&-x;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
long long sum = 0;
for(int i=1;i<=n;i++)
{
cin>>a[i].data;
a[i].index = i;
sum += a[i].data;
}
sort(a+1,a+n+1,cmp);
if(sum%2 == 1)
{
cout<<"0\n";
}else
{
memset(dp,false,sizeof(dp));
sum = sum / 2;
dp[0][0] = true;;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=sum;j++)
{
if(dp[i-1][j]) dp[i][j] = true;
else if(j>=a[i].data)
{
if(dp[i-1][j-a[i].data]) dp[i][j] = true;
}
}
}
if(dp[n][sum])
{
cout<<"1\n";
int index = -1;
int ans = 0x7fffffff;
for(int i=1;i<=n;i++)
{
if(lowbit(a[i].data) < ans)
{
ans = lowbit(a[i].data);
index = a[i].index;
}
}
cout<<index<<endl;
}else cout<<"0\n";
}
return 0;
}