1.13 构造

1512D - Corrupted Array

题意

给出序列b,含有n+2个元素,其中第n+1个元素是前n个元素的和,第n+2个元素为任意数字,序列b内元素的顺序可能是紊乱的,如果有满足条件的序列,将前n个元素输出,否则输出-1

思路

给出了前n个元素的和,就代表可能要排序。将n+2个元素排序。因为有一个元素为前n个元素的和,所以它一定是最大的或者第二大的。判断即可

void solve() {
	int n, m;
	cin >> n;
	m = n + 2;
	vector<int> a(m + 1);
	for (int i = 1; i <= m; i ++) {
		cin >> a[i];
	}
	
	sort(a.begin() + 1, a.end());
	
	LL sum = 0;
	
	for (int i = 1; i <= n; i ++) {
		sum += a[i];
	}
	
	if (sum > a[m]) {
		cout << -1 << endl;
		return ;
	} else if (sum == a[m] || sum == a[m - 1]) {
		for (int i = 1;  i <= n; i ++) {
			cout << a[i] << " \n"[i == n];
		}
	} else if (sum < a[m]) {
		sum = sum + a[m - 1] - a[m];
		int flag = -1;
		for (int i = 1; i <= n; i ++) {
			if (a[i] == sum) {
				flag = i;
				break;
			}
		}
		
		if (flag == -1) {
			cout << -1 <<  endl;
			return ;
		}
		
		for (int i = 1; i <= n + 1; i ++) {
			if (i == flag) continue;
			cout << a[i] << " \n"[i == n + 1];
		}
	}
}

\[\]

1512C - A-B Palindrome

题意

给出a,b,和一个只含有‘1’,‘0’,‘?’的字符串,要求构造出一个只含有a个‘0’,b个‘1’的回文字符串,通过将‘?’改成‘0’或者‘1’。问是否可以

思路

正常模拟即可。既然是回文字符串,首先将题目中给出的字符串整理一遍,将当前的s[i]和s[n - i + 1]进行比较。然后统计字符串中01数量是否超限,在判断字符串中是否存在成对儿的‘?’或者在中间的单个‘?’,若有则看01哪个有多余的,改成它即可。否则判负。最后将字符串倒序和正序比较,是回文字符串且a,b恰好用完即为所求,否则判负

void solve() {
	int x, y;
	cin >> x >> y;
	string s;
	cin >> s;
	s = " " + s;
	int n = x + y;
	for (int i = 1; i <= n; i ++) {
		if (s[i] != '?') {                                         //如果当前字符有值
			if (s[n - i + 1] != '?' && s[i] != s[n - i + 1]) {    //如果对面字符有值且不和当前字符相等,-1
				cout << -1 << endl;
				return ;
			} else if (s[n - i + 1] == '?'){                      //如果对面字符无值,那么赋成和当前字符相等的值
				s[n - i + 1] = s[i];
			}
		} else {
			if (s[n - i + 1] != '?') {                          //如果当前字符无值 且对面有值
				s[i] = s[n - i + 1];
			}
		}
	}
	
	for (int i = 1; i <= n; i ++) {                            //检查一下还剩多少01
		if (s[i] == '0') x --;
		if (s[i] == '1') y --;
	}
	
	for (int i = 1; i <= n; i ++) {
		if (s[i] == '?') {
			if (i != n - i + 1) {                           //若有成对儿的问号
				if (x >= 2) {
					x -= 2;
					s[i] = s[n - i + 1] = '0';
				} else if (y >= 2) {
					y -= 2;
					s[i] = s[n - i + 1] = '1';
				}else {
					cout << -1 << endl;
					return ;
				}
			}else {                                      //若是单个问号
				if (x == 1) {
					x --;
					s[i] = '0';
				}else if (y == 1) {
					y --;
					s[i] = '1';
				}else {
					cout << -1 << endl;
					return ;
				}
			}
		}
	}
	
	string t = s.substr(1);
	string h = t;
	reverse(t.begin(), t.end());
	bool ok = 0;
	if (t == h) ok = 1;
	if (ok && !x && !y) {
		cout << h << endl;
	} else cout << -1 << endl;
}

\[\]

1497C1 - k-LCM (easy version)

题意

给出数字n和k个数字,要求这k个数字之和为n且他们的最小公倍数小于等于n/2。输出这k个数字

思路

这个版本的k只有3,所以直接找规律即可。首先可以被三整除的一定可以分为3份且满足题意,不能被三整除的,但是是奇数,则可以由1和两个偶数组成,也是满足题意的
剩下只有偶数部分,偶数也分为两类,一种是8,16,32这类可以被四整除的,那么直接分为1/2,1/4,1/4即可。否则就将偶数减二再对半分也一定是满足题意的。

void solve() {
	int n, k;
	cin >> n >> k;
	if (n % 3 == 0) {
		for (int i = 1; i <= 3; i ++) cout << n / 3 << " \n"[i == 3];
	}else if (n % 2 == 1) {
		n --;
		cout << n / 2 << ' ' << n / 2 << ' ' << 1 << endl;
	}else {
		int t = n - 2;
		if (t % 4 == 0) {
			cout << t / 2 << ' ' << t / 2 << ' ' << 2 << endl;
		}else {
			cout << n / 2 << ' ' << n / 4 << ' ' << n / 4 << endl;
		}
	}
}

\[\]

1521B - Nastia and a Good Array

题意

给出n个数字,可以对它进行若干操作,然后要求使这组数字相邻之间的gcd为1。操作为:选择任意下标i, j将a[i], a[j]改成x, y。且min(a[i], a[j]) == min(x, y)

思路

题目限制操作次数不大于n,那么我们可以进行n次操作。因为我们知道连续的两个数一定gcd为1,如gcd(2,3) = 1, gcd(23, 24) = 1。那么就想如何将这组数构造成这种连续的数字。
那么首先找到数组中最小的数,然后将它换到开头,然后对后面n-1个数字进行更改,每个都在前一个数字的基础上加一即可。
如:9 6 3 11 15
首先:3 6 9 11 15
然后:
3 4 9 11 15
3 4 5 11 15
3 4 5 6 15
3 4 5 6 7
结束。正好n次操作

struct node{
	int i, j, x, y;
};
 
//注意观察N的大小
void solve() {
	int n;
	cin >> n;
	vector<int> a(n + 1);
	int mnv = INF, flag = -1;
	for (int i = 1; i <= n; i ++) {
		cin >> a[i];
		if (mnv > a[i]) {
			mnv = a[i];
			flag = i;
		}
	}
	
	vector<node> v;
	
	if (flag != 1)
		v.push_back({1, flag, mnv, a[1]});
	
	int x = mnv;
	
	for (int i = 2; i <= n; i ++) {
		v.push_back({1, i, mnv, ++ x});
	}
	
	cout << v.size() << endl;
	for (auto q : v) {
		cout << q.i << ' ' << q.j << ' ' << q.x << ' ' << q.y << endl; 
	}
}

\[\]

1453B - Suffix Operations

题意

给出序列a,有两种操作:
1.后缀-1
2.后缀+1
你需要让a的所有元素全部相等,同时你可以改变一个数字以减少操作次数
问最少操作数是多少

思路

这种题应该一眼差分,但是没想出来。看的题解,枚举每个元素,找出一个波峰或者波谷,让拐点等于两端中的任意一段即可最大程度降低操作次数,其中对于第一个元素和最后一个元素只需要跟相邻元素比较即可

void solve() {
	int n;
	cin >> n;
	vector<LL> a(n + 1);
	for (int i = 1; i <= n; i ++) {
		cin >> a[i];
	}
	
	LL sum = 0, mx = -INF;
	
	for (int i = 2; i <= n; i ++) {
		sum += abs(a[i - 1] - a[i]);
	}
	
	mx = max(mx, abs(a[1] - a[2]));
	mx = max(mx, abs(a[n - 1] - a[n]));
	
	for (int i = 2; i < n; i ++) {
		mx = max(mx, abs(a[i - 1] - a[i]) + abs(a[i + 1] - a[i]) - abs(a[i - 1] - a[i + 1]));
	}
	
	cout << sum - mx << endl;
}

\[\]

1421C - Palindromifier

题意

给出一个字符串S,你有两种操作:
1.从下标i一直到s[2],将其倒转加在字符串前面
2.从下标i一直到s[n - 1],将其倒转加在字符串后面
问是否可以通过这两种操作,不超过30次将字符串变成回文字符串

思路

这题很巧妙,直接观察多试几次就可以知道规律
先找到倒数第二个字符,然后用操作2,将这个字符放在字符串后面,然后在更新后的字符串的倒数第二个字符,也就是原来字符的最后一个进行操作1,然后字符串里回文字符串就只有最后一个字符的差异,而此时会神奇的发现字符串的第二个字符就是那个字符,在用一次操作1即可
模拟一遍:
原字符串:xyzq
1.xyzqz
2.qzyxyzqz
3.zqzyxyzqz

最后我在前面判了是不是一开始就是回文串,但其实无所谓

void solve() {
	string s, t;
	cin >> s;
	t = s;
	reverse(t.begin(), t.end());
	if (s == t) {
		cout << 0 << endl;
		return ;
	}
	int n = s.size();
	cout << 3 << endl;
	cout << "R " << n - 1 << endl;
	cout << "L " << n << endl;
	cout << "L " << 2 << endl;
}

总结:1500——1600的题目写的还很艰难,1200——1300很舒服,1400基本可以动手,感觉思维有点提升

posted @ 2023-01-13 19:57  nobodyL  阅读(23)  评论(0)    收藏  举报