Codeforces Round 640 (Div. 4)

Codeforces Round 640 (Div. 4) 题解

A. Sum of Round Numbers

题目大意:

给你一个整数n,1<=n<=104n, 1 <= n <= 10^4n,1<=n<=104,问最少拆成几个四舍五入数的和

四舍五入数的定义为:除了最高位其它位都为0的整数

例如,以下数字都是四舍五入数: 400040004000 , 111 , 999 , 800800800 , 909090

下列数字不是: 110110110 , 707707707 , 222222222 , 100110011001 .

样例输入:

5
5009
7
9876
10000
10

样例输出

2
5000 9
1
7 
4
800 70 6 9000 
1
10000 
1
10 

思路

从右往左依次判断每一位,遇到不为0的数位就拆分

代码

#include <bits/stdc++.h>
using namespace std;

void solve() {
	int n; cin >> n;
	vector<int> a;
	for(int i = 10; i / 10 <= n; i *= 10) {
		if(n % i != 0) {
			a.push_back(n % i);
			n -= n % i;
		}
	}
	cout << a.size() << endl;
	for(auto i : a) cout << i << " ";
	cout << endl;	
}

signed main() {
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}

B. Same Parity Summands

题目大意:

给你两个正整数 nnn ( 1≤n≤1091 \le n \le 10^91n109 )和 kkk ( 1≤k≤1001 \le k \le 1001k100 )。( 1≤n≤1091 \le n \le 10^91n109 ) 和 kkk ( 1≤k≤1001 \le k \le 1001k100 )。

将数字 nnn 表示为具有相同奇偶性的 kkk 个正整数之和(除以 222 时具有相同的余数)。

换句话说,找出 a1,a2,…,aka_1, a_2, \ldots, a_ka1,a2,,ak ,使所有 ai>0a_i>0ai>0n=a1+a2+…+akn = a_1 + a_2 + \ldots + a_kn=a1+a2++ak 和所有 aia_iai 同时为偶数或所有 aia_iai 同时为奇数。

如果不存在这样的表示,请报告。

样例输入:

8
10 3
100 4
8 7
97 2
8 8
3 10
5 3
1000000000 9

样例输出

YES
4 2 4
YES
55 5 5 35
NO
NO
YES
1 1 1 1 1 1 1 1
NO
YES
3 1 1
YES
111111110 111111110 111111110 111111110 111111110 111111110 111111110 111111110 111111120

思路

分类讨论

  • k>nk > nk>n的情况一定不可能,直接输出 NONONO
  • 如果k,nk,nk,n的奇偶性一样,那么nnn可以拆成 1+1+1...+(n−k+1)1 + 1 + 1 ... + (n - k + 1)1+1+1...+(nk+1)
  • 如果nnn为奇数,kkk为偶数,那么不管是kkk个奇数相加还是kkk个偶数相加结果都为偶数,一定不可能,直接输出NONONO
  • 如果nnn为偶数,kkk为奇数
    • kkk个奇数相加,结果一定为奇数,不行
    • kkk个偶数相加,拆成形如2+2+2...+(n−k∗2+2)2 + 2 + 2 ... +(n - k * 2 + 2)2+2+2...+(nk2+2)的式子,需满足2∗k<=n2 * k <= n2k<=n

代码

#include <bits/stdc++.h>
using namespace std;

void solve() {
	int n, k; cin >> n >> k;
	if(k > n) {
		cout << "NO\n";
		return ;
	}
	if(k % 2 == n % 2) {
		cout << "YES\n";
		for(int i = 2; i <= k; i++)
			cout << 1 << " ";
		cout << n - k + 1 << endl;
	} else {
		if(n % 2 == 0) {
			if(k * 2 <= n) {
				cout << "YES\n";
				for(int i = 2; i <= k; i++)
					cout << 2 << " ";
				cout << n - (k + k - 2) << endl;
			} else {
				cout << "NO\n";
			}
		} else {
			cout << "NO\n";
		}
	}
	
}

signed main() {
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}

C. K-th Not Divisible by n

题目大意:

给定两个正整数 nnnkkk 。打印不能被 nnn 整除的第kkk个正整数 。

例如,如果 n=3n=3n=3 n=3n = 3n=3k=7k=7k=7 ,则所有不能被 333 整除的数为: 1,2,4,5,7,8,10,11,13…1, 2, 4, 5, 7, 8, 10, 11, 13 \dots1,2,4,5,7,8,10,11,13

其中第 777个数是 101010

每个测试用例都是两个正整数 nnn ( 2≤n≤1092 \le n \le 10^92n109 ) 和 kkk ( 1≤k≤1091 \le k \le 10^91k109 )。

样例输入

6
3 7
4 12
2 1000000000
7 97
1000000000 1000000000
2 1

样例输出

10
15
1999999999
113
1000000001
1

思路

我们把正整数拆成每行nnn个数字,例如n=5,k=16n = 5, k = 16n=5,k=16

 1  2  3  4  5
 6  7  8  9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
...

不难发现,只有每一行的最后一个数字能被 nnn 整除

我们先判断第 kkk 个不能被nnn整除的数字在第几行

v=k/(n−1)v = k / (n - 1)v=k/(n1)

两种情况:

  • k/(n−1)k / (n - 1)k/(n1)的余数为000,那么说明在第vvv行的倒数第二个,结果为v∗n−1v * n - 1vn1
  • 余数不为000,那么往前加余数个位置即可,结果为v∗n+k%(n−1)v * n + k \% (n - 1)vn+k%(n1)

代码

#include <bits/stdc++.h>
using namespace std;

void solve() {
	int n, k; cin >> n >> k;
	int vis = k / (n - 1);
	if(k % (n - 1) == 0) cout << vis * n - 1 << endl;
	else cout << (vis * n) + k % (n - 1) << endl;
}

signed main() {
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}

D. Alice, Bob and Candies

题目大意:

一排有 nnn 颗糖果,从左到右从 111nnn 进行编号。 第iii 个糖果的大小是 aia_iai

爱丽丝和鲍勃玩一个有趣又美味的游戏:他们吃糖果。爱丽丝从左到右吃糖,鲍勃从右到左吃糖。如果所有的糖果都吃完了,游戏就结束了。

这个过程是由动作组成的。在移动过程中,玩家从她/他的身边吃一个或多个糖果(Alice从左边吃,Bob从右边吃)。

爱丽丝先走了。在第一步中,她会吃 111 颗糖果(它的大小是 a1a_1a1 )。然后,每个连续的移动,参与者交替——也就是说,鲍勃走第二步,然后是爱丽丝,然后是鲍勃,以此类推。

在每次移动中,玩家计算在当前移动中吃掉的糖果的总大小。一旦这个数字严格大于其他玩家在之前的移动中吃掉的糖果的总大小,当前玩家就会停止吃糖果,移动也就结束了。换句话说,在一次移动中,玩家吃掉尽可能少的糖果,这样在这次移动中吃掉的糖果大小的总和就严格大于另一个玩家在前一次移动中吃掉的糖果大小的总和。如果没有足够的糖果来进行移动,那么玩家就会吃掉所有剩余的糖果,游戏就会结束。

例如,如果 n=11n=11n=11a=[3,1,4,1,5,9,2,6,5,3,5]a=[3,1,4,1,5,9,2,6,5,3,5]a=[3,1,4,1,5,9,2,6,5,3,5] ,则:

-第1步:爱丽丝吃了一个大小为 333 的糖果,糖果的序列变成 [1,4,1,5,9,2,6,5,3,5][1,4,1,5,9,2,6,5,3,5][1,4,1,5,9,2,6,5,3,5]
-第2步:Alice在前一步中吃了 333 ,这意味着Bob必须吃 444 或更多。鲍勃吃了一个大小为 555 的糖果,糖果的序列就变成了 [1,4,1,5,9,2,6,5,3][1,4,1,5,9,2,6,5,3][1,4,1,5,9,2,6,5,3]
-第3步:鲍勃在前一步吃了 555 ,这意味着爱丽丝必须吃 666 或更多。爱丽丝吃了三颗总尺寸为 1+4+1=61+4+1=61+4+1=6 的糖果,糖果的序列变成了 [5,9,2,6,5,3][5,9,2,6,5,3][5,9,2,6,5,3]
-第4步:Alice在前一步吃了 666 ,这意味着Bob必须吃 777 或更多。Bob吃了两块总尺寸为 3+5=83+5=83+5=8 的糖果,糖果的序列变成了 [5,9,2,6][5,9,2,6][5,9,2,6]
-第5步:鲍勃在前一步吃了 888 ,这意味着爱丽丝必须吃 999 或更多。爱丽丝吃了两个总尺寸为 5+9=145+9=145+9=14 的糖果,糖果的序列变成 [2,6][2,6][2,6]
-第6步(最后一步):爱丽丝在前一步吃了 141414 ,这意味着鲍勃必须吃 151515 或更多。这是不可能的,所以鲍勃吃掉了剩下的两块糖果,游戏结束了。

打印游戏中移动的数量和两个数字:

  • aaa -游戏中爱丽丝吃掉的所有糖果的总大小;
  • bbb - Bob在游戏中吃掉的所有糖果的总大小。

样例输入

7
11
3 1 4 1 5 9 2 6 5 3 5
1
1000
3
1 1 1
13
1 2 3 4 5 6 7 8 9 10 11 12 13
2
2 1
6
1 1 1 1 1 1
7
1 1 1 1 1 1 1

样例输出

6 23 21
1 1000 0
2 1 2
6 45 46
2 2 1
3 4 2
4 4 3

思路

根据题意模拟即可,注意细节

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

void solve() {
	int n; cin >> n;
	vector<int> v(n);
	for(auto &i : v) 
		cin >> i;
	int l = 0, r = n - 1;
	int L = 0, R = 0, bef = 0, res = 0;
	int visl = 0, visr = 0;
	while(l <= r) {
		res++;
		while(visl <= bef and l <= r) {
			visl += v[l];
			l++;
		}
		L += visl;
		if(visl <= bef or l > r) break;
		bef = visl;
		res++;
		while(visr <= bef and l <= r) {
			visr += v[r];
			r--;
		}
		R += visr;
		if(visr <= bef or l > r) break;
		bef = visr;
		visl = visr = 0;		
	}
	cout << res << " " << L << " " << R << endl;
}

signed main() {
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}

E. Special Elements

题目大意:

给出了数组 a=[a1,a2,…,an]a=[a_1, a_2, \ldots, a_n]a=[a1,a2,,an] ( 1≤ai≤n1 \le a_i \le n1ain )。它的元素 aia_iai 被称为特殊如果存在一对索引 lllrrr ( 1≤l<r≤n1 \le l < r \le n1l<rn )使得 ai=al+al+1+…+ara_i = a_l + a_{l+1} + \ldots + a_rai=al+al+1++ar 。换句话说,如果一个元素可以表示为数组中两个或多个连续元素的和(无论它们是否特殊),则该元素被称为特殊元素。

输出给定数组 aaa 中特殊元素的个数。

例如,如果 n=9n=9n=9a=[3,1,4,1,5,9,2,6,5]a=[3,1,4,1,5,9,2,6,5]a=[3,1,4,1,5,9,2,6,5] ,那么答案是 555

  • a3=4a_3=4a3=4 是一个特殊元素,因为 a3=4=a1+a2=3+1a_3=4=a_1+a_2=3+1a3=4=a1+a2=3+1
  • a5=5a_5=5a5=5 是一个特殊元素,因为 a5=5=a2+a3=1+4a_5=5=a_2+a_3=1+4a5=5=a2+a3=1+4
  • a6=9a_6=9a6=9 是一个特殊元素,因为 a6=9=a1+a2+a3+a4=3+1+4+1a_6=9=a_1+a_2+a_3+a_4=3+1+4+1a6=9=a1+a2+a3+a4=3+1+4+1
  • a8=6a_8=6a8=6 是一个特殊元素,因为 a8=6=a2+a3+a4=1+4+1a_8=6=a_2+a_3+a_4=1+4+1a8=6=a2+a3+a4=1+4+1
  • a9=5a_9=5a9=5 是一个特殊元素,因为 a9=5=a2+a3=1+4a_9=5=a_2+a_3=1+4a9=5=a2+a3=1+4

请注意,数组 aaa 中的某些元素可能是相等的——如果有几个元素是相等且特殊的,则应将所有元素都计算在答案中。

第一行包含一个整数 ttt ( 1≤t≤10001 \le t \le 10001t1000 )—输入中的测试用例的数量。然后是 ttt 测试用例。

每个测试用例用两行给出。第一行包含一个整数 nnn ( 1≤n≤80001 \le n \le 80001n8000 )——数组 aaa 的长度。第二行包含整数 a1,a2,…,ana_1, a_2, \dots, a_na1,a2,,an ( 1≤ai≤n1 \le a_i \le n1ain )。

保证输入中所有测试用例 nnn 的值之和不超过 800080008000

样例输入

5
9
3 1 4 1 5 9 2 6 5
3
1 1 2
5
1 1 1 1 1
8
8 7 6 5 4 3 2 1
1
1

样例输出

5
1
0
4
0

思路

由于数据范围很小,我们只需要统计800080008000以内的结果。

创建mpmpmp数组统计ai<=8000a_i <= 8000ai<=8000每个数出现的次数。

然后双重循环暴力寻找左右端点,如果和出现过就加上,注意加完之后和要清空,否则会重复计算。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

int mp[8010];
void solve() {
	memset(mp, 0, sizeof(mp));
	int n; cin >> n;
	vector<int> v(n + 1);
	for(int i = 1; i <= n; i++) {
		cin >> v[i];
		mp[v[i]]++;
	}	
	for(int i = 1; i <= n; i++)
		v[i] += v[i - 1];
	int res = 0;
	for(int i = 1; i + 1 <= n; i++) {
		for(int j = i + 1; j <= n; j++) {
			if(v[j] - v[i - 1] <= 8000) {
				res += mp[v[j] - v[i - 1]];
				mp[v[j] - v[i - 1]] = 0;
			} else {
				break;
			}
		}
	}
	cout << res << endl;
}

signed main() {
	
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}	

F. Binary String Reconstruction

题目描述:

对于某些二进制字符串 sss (即每个字符 sis_isi 是‘0’或‘1’),将写入所有连续(相邻)字符对。

换句话说,写入长度为 222 的所有子字符串。对于每一对(长度为 222 的子串),计算其中“1”(1)的个数。

给你三个数字:

  • n0n_0n0 -连续字符对(子字符串)的个数,其中1的个数等于 000
  • n1n_1n1 -连续字符对(子字符串)的个数,其中1的个数等于 111
  • n2n_2n2 -连续字符对(子字符串)的个数,其中1的个数等于 222

例如,对于字符串 s=s=s= “1110011110“,将写入以下子字符串:”11”,“11”,“10”,“00”,“01”,“11”,“11”,“11”,“11”,“11”,“10”。因此, n0=1n_0=1n0=1 , n1=3n_1=3n1=3 , n2=5n_2=5n2=5

您的任务是从给定值 n0,n1,n2n_0, n_1, n_2n0,n1,n2 中恢复任何合适的二进制字符串 sss 。可以保证至少有一个数字 n0,n1,n2n_0, n_1, n_2n0,n1,n2 大于 000 。此外,还保证存在解决方案。

题目大意:

三个正整数 a,b,ca, b, ca,b,c,构造一个01字符串

其中子串00的数量为aaa,字串0110的数量为bbb,字串11的数量为ccc

例如 a=2,b=3,c=4a = 2, b = 3, c = 4a=2,b=3,c=4

符合条件的字符串为:000111110100011111010001111101

样例输入:

7
1 3 5
1 1 1
3 9 3
0 1 0
3 1 2
0 0 3
2 0 0

样例输出:

1110011110
0011
0110001100101011
10
0000111
1111
000

思路

分类讨论

  • b==0b == 0b==0,说明没有分界点,那么a,ca, ca,c肯定有一个为000,直接输出a+1a + 1a+10或者c+1c + 1c+11即可。
  • bbb大于000的情况
    • 先输出a+1a + 1a+1000,再输出c+1c + 1c+1111,由于前面一定包含一个交界点,最后再输出长度为b−1b - 1b1000开头的010101
      • 例:a=4,b=5,c=2a = 4, b = 5, c = 2a=4,b=5,c=2,输出:000001110101
        • 先输出a+1a + 1a+100000000
        • 再输出c+1c + 1c+1111111
        • 再输出长度为b−1b - 1b1000开头的010101串:0101

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

void solve() {
	int a, b, c;
	cin >> a >> b >> c;
	if(b == 0) {
		if(a != 0)
			for(int i = 0; i <= a; i++)
				cout << 0;
		if(c != 0)
			for(int i = 0; i <= c; i++)
				cout << 1;
		cout << endl;
		return ;
	}

	for(int i = 0; i <= a; i++)
		cout << "0";
	for(int i = 0; i <= c; i++)
		cout << "1";
	for(int i = 2; i <= b; i++)
		cout << i % 2;
	cout << endl;
}

signed main() {
	
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}	

G. Special Permutation

题目描述:

长度为 nnn 的排列是一个数组 p=[p1,p2,…,pn]p=[p_1,p_2,\dots,p_n]p=[p1,p2,,pn] ,其中包含从 111nnn (包括)的所有整数,而且每个数字只出现一次。

例如, p=[3,1,4,2,5]p=[3,1,4,2,5]p=[3,1,4,2,5] 是长度为 555 的排列。

对于给定的数 nnn ( n≥2n \ge 2n2 ),找到一个排列 ppp ,其中任意两个相邻元素的绝对差值(即差值的绝对值)在 222444 之间,包括。

正式地,为每个 iii ( 1≤i<n1 \le i < n1i<n )找到 2≤∣pi−pi+1∣≤42 \le |p_i - p_{i+1}| \le 42pipi+14 的排列 ppp

为给定的整数 nnn 打印任何这样的排列,或者确定它不存在。

题目大意:

给你一个整数 nnn,把1−n1 - n1n里面的所有数字重新排列,要求最后的结果为相邻的每两个数字绝对值差在2−42 - 424之间。

如果不能就输出 −1-11

样例输入

6
10
2
4
6
7
13

样例输出

9 6 10 8 4 7 3 1 5 2 
-1
3 1 4 2 
5 3 6 2 4 1 
5 1 3 6 2 4 7 
13 9 7 11 8 4 1 3 5 2 6 10 12 

思路

不难发现,n<=3n <= 3n<=3的情况,无论怎么排都不可能,直接输出−1-11

然后分两种情况

  • nnn为偶数,先从小到大输出所有偶数,再输出第二大的奇数跟最大的奇数,然后剩下的奇数从大到小输出。
    • 例:n=10n = 10n=10,排列为2   4   6   8   10   7   9   5   3   12\ \ \ 4\ \ \ 6\ \ \ 8\ \ \ 10\ \ \ 7\ \ \ 9\ \ \ 5\ \ \ 3\ \ \ 12   4   6   8   10   7   9   5   3   1
      • 先从小到大输出所有偶数: 2   4   6   8   102\ \ \ 4\ \ \ 6\ \ \ 8\ \ \ 102   4   6   8   10
      • 再输出第二大的奇数跟最大的奇数: 7   97\ \ \ 97   9
      • 然后剩下的奇数从大到小输出:5   3   15\ \ \ 3\ \ \ 15   3   1
  • nnn为奇数,跟上面的方法类似,只不过是先输出所有奇数,再输出第二大的偶数跟最大的偶数,然后剩下的偶数从大到小输出。
    • 例:n=9n = 9n=9,排列为1   3   5   7   9   6   8   4   21\ \ \ 3\ \ \ 5\ \ \ 7\ \ \ 9\ \ \ 6\ \ \ 8\ \ \ 4\ \ \ 21   3   5   7   9   6   8   4   2
      • 先从小到大输出所有奇数: 1   3   5   7   91\ \ \ 3\ \ \ 5\ \ \ 7\ \ \ 91   3   5   7   9
      • 再输出第二大的偶数跟最大的偶数: 6   86\ \ \ 86   8
      • 然后剩下的偶数从大到小输出:4   24\ \ \ 24   2

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

void solve() {
	int n; cin >> n;
	if(n <= 3) {
		cout << - 1 << "\n";
		return ;
	}
	if(n % 2 == 0) {
		for(int i = 2; i <= n; i += 2)
			cout << i << " ";
		cout << n - 3 << " " << n - 1 << " ";
		for(int i = n - 5; i >= 1; i -= 2)
			cout << i << " ";
		cout << "\n"; 
	} else {
		for(int i = 1; i <= n; i += 2)
			cout << i << " ";
		cout << n - 3 << " " << n - 1 << " ";
		for(int i = n - 5; i >= 2; i -= 2)
			cout << i << " ";
		cout << "\n";
	}
}

signed main() {
	
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值