Codeforces Round #717 (Div. 2) A-D

##A. Tit for Tat

Description

Given an array aa of length nn, you can do at most kk operations of the following type on it:

  • choose 2 2 2 different elements in the array, add 1 1 1 to the first, and subtract 1 1 1 from the second. However, all the elements of aa have to remain non-negative after this operation.

What is lexicographically the smallest array you can obtain?

An array x x x is lexicographically smaller than an array y y y if there exists an index i i i such that x i < y i x_i<y_i xi<yi, and x j = y j x_j=y_j xj=yj for all 1 ≤ j < i 1≤j<i 1j<i. Less formally, at the first index ii in which they differ, x i < y i x_i<y_i xi<yi.

Input

The first line contains an integer tt ( 1 ≤ t ≤ 20 1≤t≤20 1t20) – the number of test cases you need to solve.

The first line of each test case contains 2 2 2 integers n n n and k k k ( 2 ≤ n ≤ 100 2≤n≤100 2n100, 1 ≤ k ≤ 10000 1≤k≤10000 1k10000) — the number of elements in the array and the maximum number of operations you can make.

The second line contains nn space-separated integers a 1 a1 a1, a 2 a2 a2, ……, a n an an ( 0 ≤ a i ≤ 100 0≤ai≤100 0ai100) — the elements of the array a a a.

Output

For each test case, print the lexicographically smallest array you can obtain after at most k k k operations.

Example
Input
2
3 1
3 1 4
2 10
1 0
Output
2 1 5 
0 1 
题目大意与分析

这题就是说给你一个长度为 n n n 的数组,你可以最多进行 k k k 次操作,每次操作可以选取两个数字,

一个加一,一个减一,问你可以得到的字典序最小的数组是什么

因为要得到字典序最小,因此要让前面的数字尽可能的小,又因为每次可以取两个数,因此每次从取最前面不为 0 0 0 的数和最后一个数,让前面的减一,后面的加一,这样进行k次操作后所能得到的数组一定是字典序最小的

AC代码
#include<iostream>
#include<algorithm>
 
using namespace std;
const int N = 1E5 + 10;
int a[N];
int main() {
	int t, n, k;
	cin >> t;
	while(t--) {
		cin >> n >> k;
		for(int i = 1; i <= n; i++) {
			cin >> a[i];
		}
		for(int i = 1; i < n; i++) {
			if(a[i] >= k) {
				a[i] -= k; 
				a[n] += k;
				break;
			} else {
				k -= a[i];
				a[n] += a[i];
				a[i] = 0;	
			}
		}
		for(int i = 1; i <= n; i++) {
			cout << a[i] << " ";
		}
		cout << endl;
	}
	return 0;
} 

B. AGAGA XOOORRR

Description

Baby Ehab is known for his love for a certain operation. He has an array A A A of length n n n, and he decided to keep doing the following operation on it:

  • he picks 2 2 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 2 2 elements remaining.

Input

The first line contains an integer t t t ( 1 ≤ t ≤ 15 1≤t≤15 1t15) — the number of test cases you need to solve.

The first line of each test case contains an integers n n n ( 2 ≤ n ≤ 2000 2≤n≤2000 2n2000) — the number of elements in the array a a a.

The second line contains nn space-separated integers a 1 a_1 a1, a 2 a_2 a2, ……, a n a_n an ( 0 ≤ a i < 230 0≤ai<230 0ai<230) — the elements of the array a a a.

Output

If Baby Ehab can make all elements equal while leaving at least 2 2 2 elements standing, print “YES”. Otherwise, print “NO”.

Example
Input
2
3
0 2 2
4
2 3 1 10
Output
YES
NO
题目大意与分析

这题的题目意思是说给定你一个长度为 n n n 的数组,你每次可以选择任意相邻的两个元素,然后把这两个元素从数组中删除,然后把它们的异或的结果放入数组中,位置和删去元素的位置一样,问你经过若干次这样的操作是否可以把数组变为元素全部一样的,并且最后剩下的元素至少为 2 2 2

如果可以输出 Y E S YES YES ,否则输出 N O NO NO

首先由异或运算是符合结合律的,对于 a ∧ b ∧ c a \wedge b \wedge c abc 先运算 a ∧ b a \wedge b ab 或者 b ∧ c b \wedge c bc 得到的答案一样,所以可以先求一次前缀异或

然后如果数组的大小是偶数,并且所有的元素都相同,那么最后的异或结果一定为0

如果数组的大小为奇数,并且所有的元素都相同,那么最后的异或结果一定为这个元素本身

由于最后剩下的元素至少为 2 2 2 个,并且每次是取相邻的元素进行异或,那么可以把所有元素分为两份,如果两部分的所有元素异或之后的结果相同,那么可以说明是一定可以化为至少两个元素相同的数组

但是正如上面分析的,这种情况只是可以满足最后化为数组大小为偶数的情况,奇数的情况没有考虑

奇数的情况怎么考虑呢,因为最少为 2 2 2个,所以奇数至少为 3 3 3, 又因为超过 3 3 3 的情况,可以让相邻的两两相同的去异或,最后一定会只剩三个相同元素的情况,所以我们可以去找三部分相同的情况

这样只要存在两部分相同或者三部分相同,那么必然可以化为至少 2 2 2 个元素全部相同的数组

需要注意的是这里我们看区间的话,只能 ( 1 , i ) , ( i + 1 , j − 1 ) , ( j , n ) (1,i),(i + 1, j-1),(j, n) (1,i),(i+1,j1),(j,n) 这样三个区间去看

而不能 ( i , i − 1 ) , ( i , j ) , ( j + 1 , n ) (i,i-1),(i,j),(j+1,n) (i,i1),(i,j),(j+1,n) 因为这样存在前后端的两个区间不存在的情况,无法满足至少存在两个元素存在的情况

AC代码
#include<iostream>
#include<algorithm>
 
using namespace std;
const int N = 3E3 + 10;
int a[N], f[N][N];
 
int main() {
	int t, n, k;
	cin >> t;
	while(t--) {
		cin >> n;
		for(int i = 1; i <= n; i++) {
			cin >> a[i];
			a[i] ^= a[i - 1];
		}
		for(int i = 1; i <= n; i++) {
			for(int j = i; j <= n; j++) {
				f[i][j] = a[j] ^ a[i - 1];
			}
		}
		bool flag = 0;
		for(int i = 1; i < n; i++) {
			if(flag) break;
			for(int j = i; j <= n; j++) {
				if(f[1][i] == f[i + 1][n]) {
					flag = 1; break;
				} else if(f[1][i] == f[i + 1][j - 1] && f[i + 1][j - 1] == f[j][n]) {
					flag = 1; break;
				}
			}
		}
		if(flag) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
} 

C. Baby Ehab Partitions Again

Description

Baby Ehab was toying around with arrays. He has an array a a a of length n n n. He defines an array to be good if there’s no way to partition it into 2 2 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 aa so that it becomes a good array. Can you help him?

A sequence bb is a subsequence of an array a a a if bb can be obtained from aa by deleting some (possibly zero or all) elements. A partitioning of an array is a way to divide it into 2 2 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 n n ( 2 ≤ n ≤ 100 2≤n≤100 2n100) — the length of the array a a a.

The second line contains n n n integers a 1 a_1 a1, a 2 a_2 a2, ……, a n a_n an ( 1 ≤ a i ≤ 2000 ) 1≤ai≤2000) 1ai2000) — the elements of the array a a 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.

Example
Input
4
6 3 9 12
Output
1
2
Input
2
1 2
Output
0
题目大意与分析

这题是说给你一个长度为 n n n 的数组,你可以把这个数组取出来两个子序列,并且这两个子序列不能取同一个下标的,并且两个要包含数组的所有元素,问你最最少需要去掉多少个元素,才能保证无论怎么分,这两个子序列的和始终不一样,然后输出去掉元素的下标

假设第一个子序列的和为 s u m 1 sum1 sum1, 第二个子序列的和为 s u m 2 sum2 sum2 s u m = s u m 1 + s u m 2 sum=sum1+sum2 sum=sum1+sum2

如果两个相同的话,说明总的和一定是偶数,所以如果本来数组的和是奇数的话,那么一个元素都不用去就可以满足条件

如果是偶数呢,但是如果 s u m / 2 sum/2 sum/2 不存在呢,说明是不是怎么分派,始终不可能一样,所以这种情况也是一个元素都不用去掉就可以

如果是偶数,并且 s u m / 2 sum/2 sum/2 存在呢,这种情况说明一开始可以分为 s u m 1 = = s u m 2 sum1==sum2 sum1==sum2,这种情况该去掉多少个数呢,根据一开始分析的,如果所有的和是奇数就一个都不用去,那是不是说明这种情况如果数组里包含一个奇数,我把它去掉,让剩下的数组的和变为奇数是不是就可以了

如果一个奇数都没有呢,因为全部是偶数并且 s u m 1 = = s u m 2 sum1==sum2 sum1==sum2, 那么我让所有的数都去除 2 2 2, 是不是效果一样的,所以这种情况我们就一直除2,直到有一个元素为奇数为止

综上:1.首先去判断原来数组的和是不是奇数

​ 2.然后如判断 s u m / 2 sum/2 sum/2 是否存在(用背包)

​ 3.从左到右遍历一遍发现一个是奇数就输出这个元素的下标,是偶数就除2,一直进行这个操作,直到出现奇数为止

AC代码
#include<iostream>
#include<algorithm>
 
using namespace std;
const int N = 1e3 + 10;
 
int f[N * 2000], a[N];
 
int main() {
	int n, sum = 0, x;
	cin >> n;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		sum += a[i];
	}
	if(sum & 1) {
		cout << "0" << endl;
		return 0;
	}
	f[0] = 1;
	sum >>= 1;
	for(int i = 1; i <= n; i++) {
		for(int j = sum; j >= a[i]; j--) {
			f[j] += f[j - a[i]];
		}
	}
	if(!f[sum]) {
		cout << "0" << endl;
		return 0;
	}
	cout << "1" << endl;
	while(1) {
		for(int i = 1; i <= n; i++) {
			if(a[i] & 1) {
				cout << i << endl;
				return 0;
			} else a[i] >>= 1;
		}
	}
	return 0;
}

D. Cut

Description

This time Baby Ehab will only cut and not stick. He starts with a piece of paper with an array a a a of length nn written on it, and then he does the following:

  • he picks a range ( l , r ) (l,r) (l,r) and cuts the subsegment a l , a l + 1 , … , a r a_l,a_{l+1},…,a_r al,al+1,,ar out, removing the rest of the array.
  • he then cuts this range into multiple subranges.
  • to add a number theory spice to it, he requires that the elements of every subrange must have their product equal to their least common multiple (LCM).

Formally, he partitions the elements of a l , a l + 1 , … , a r a_l,a_{l+1},…,a_r al,al+1,,ar into contiguous subarrays such that the product of every subarray is equal to its LCM. Now, for q q q independent ranges ( l , r ) (l,r) (l,r), tell Baby Ehab the minimum number of subarrays he needs.

Input

The first line contains 2 2 2 integers n n n and q q q ( 1 ≤ n , q ≤ 1 0 5 1≤n,q≤10^5 1n,q105) — the length of the array a a a and the number of queries.

The next line contains nn integers a 1 , a 2 , . . . a n a_1,a_2,...a_n a1,a2,...an ( 1 ≤ a i ≤ 1 0 5 1≤ai≤10^5 1ai105) — the elements of the array a a a.

Each of the next q q q lines contains 2 2 2 integers l l l and r r r ( 1 ≤ l ≤ r ≤ n 1≤l≤r≤n 1lrn) — the endpoints of this query’s interval.

Output

For each query, print its answer on a new line.

Example
Input
6 3
2 3 10 7 5 14
1 6
2 4
3 5
Output
3
1
2
题目大意与分析

给定长度为 n 的序列,有 q 个询问,每次询问一个区间,输出至少将这个区间分成多少个连续区间才能使每个区间内的数互质。
首先考虑朴素算法,每次从 l l l 开始,每次记录当前数字的素数因子,并标记,如果后面的数字的素数因子在前面出现过了,那么所需的区间数量就要加一,每次都要将前面出现的素数因子清空。

然后我们去考虑如果可以事先知道 [ l , r ] [l,r] [l,r] 的区间内都互质,那么,当 r + 1 r+1 r+1 与区间内的某个数不互质的时候,就从 l l l 跳到 r + 1 r+1 r+1

所以我们可以通过倍增的思想,每次去找当前数字到后面的所有的不互质的点

f [ i ] [ j ] f[i][j] f[i][j] 表示从 i i i 2 j 2^j 2j 步最远能到哪里

对于每次询问 [ l , r ] [l,r] [l,r] , 只要看跳了多少步就行

AC代码
#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>

using namespace std;
const int N = 1E5 + 10;
int a[N], net[N];
vector<int> v[N * 10];
int f[N][22];

void init() {
	for(int i = 2; i < N; i++) {
		for(int j = i; j < N; j += i) {
			v[j].push_back(i);
		}
	}
}

void ma(int n) {
	memset(f, 0x3f, sizeof(f));
	for(int i = 1; i < N; i++) net[i] = n + 1;
	f[n + 1][0] = n + 1;
	for(int i = n; i >= 1; i--) {
		f[i][0] = f[i + 1][0];
		for(auto & x : v[a[i]]) {
			f[i][0] = min(f[i][0], net[x]);
			net[x] = i;
		}
	}
	for(int j = 1; j <= 20; j++) {
		for(int i = 1; i + (1 << j) <= n; i++) {
			if(f[i][j - 1] > n) f[i][j] = f[i][j - 1];
			else f[i][j] = f[f[i][j - 1]][j - 1];
		}
	}
}

void solve(int l, int r) {
	int ans = 0;
	for(int i = 20; i >= 0; i--) {
		if(f[l][i] <= r) ans += (1 << i), l = f[l][i];
	}
	cout << ans + 1 << endl;
}

int main() {
	int n, q, l, r;
	cin >> n >> q;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	init(); ma(n);
	while(q--) {
		cin >> l >> r;
		solve(l, r);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值