Codeforces Round 868 (Div. 2)【解析A、B、C、D】


传送门

A. A-characteristic(暴力)

题意:给你给含有1和-1的数组,让你求出有序对(i,j),使得ai*aj=1的数目为k的序列。
思路:很显然这些有序对中的数必须是同好的,跟1的数目有关,考虑到n很小我们直接遍历所有可能的数量。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define eps 1e-9
using namespace std;
const int N = 1e4 + 5;
void solve() {
	int n, k;
	cin >> n >> k;
	for (int i = 0; i < n; i++) {
		if (i * (i - 1) / 2 + (n - i) * (n - i - 1) / 2 == k) {
			cout << "YES\n";
			vector<int> ans;
			for (int j = 0; j < i; j++) ans.push_back(1);
			for (int j = i; j < n; j++) ans.push_back(-1);
			for (int j = 0; j < n; j++) cout << ans[j] << " \n"[j == n - 1];
			return;
		}
	}
	cout << "NO\n";
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

B. Sort with Step(贪心)

题意:给你一个打乱的排列,你可以随意交换距离为k的一对数,让你判断,如果可以直接sort,那么就输出0,如果最后有两个数,不匹配,那么久输出1,如果有更多就输出-1。
思路:考虑每个数能否放到正确的位置上。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define eps 1e-9
using namespace std;
const int N = 2e5 + 5;
int a[N];
void solve() {
	int n, k;
	cin >> n >> k;
	map<int, int> mp;
	for (int i = 1; i <= n; i++) cin >> a[i], mp[a[i]] = i;
	for (int i = 1; i <= n; i++) {
		if ((mp[i] - i) % k == 0) {
			swap(a[i], a[mp[i]]);
			mp[a[mp[i]]] = mp[i];
			mp[a[i]] = i;
		}
	}
	int cnt = 0;
	for (int i = 1; i <= n; i++) {
		if (a[i] != i) cnt++;
	}
	if (!cnt) cout << 0 << '\n';
	else if (cnt == 2) cout << 1 << '\n';
	else cout << -1 << '\n';
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

C. Strongly Composite(数学、暴力)

题意:给你一个数组,把数组的积分解成b1b2b3…,其中bi是的质因子数小于等于合因子数,求出b数组长度最大可以到多少。
思路:显然这题和数组的特征没有关系,我们只需考虑总的积的质因子。考虑尽可能减少质因子的浪费,一个质因子肯定不行,两个相同的质因子是可以的,例如 2 * 2, 质因子数是1, 合因子数是1。这样对质因子的消耗最少,我们可以先取出这些质因子,剩余一下单个不同的质因子,我们发现这些质因子必须三个一组才行,3 5 7 中质因子 有 3个,合因子是4个。如果最后多出两个,我们可以任意放到一组现有的组当中。两个相同的加其他质因子,也是合法的,三个不同的加其他质因子也是合法的。
时间复杂度:nsqrt(n),这里map使用的次数很少是相当于一个较小的常数,因为1000的因子数很少,大约二十几*logn不是主要因素。

#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define eps 1e-9
using namespace std;
const int N = 2e5 + 5;
void solve() {
	int n;
	cin >> n;
	map<int, int> mp;
	for (int i = 0; i < n; i++) {
		int a;
		cin >> a;
		for (int j = 2; j * j <= a; j++) {
			if (a % j == 0) {
				int cnt = 0;
				while (a % j == 0) a /= j, cnt++;
				mp[j] += cnt;
			}
		}
		if (a > 1) mp[a]++;
	}
	ll ans = 0, sum = 0;
	for (auto i : mp) {
		ans += i.second / 2;
		sum += i.second % 2; 
	}
	cout << ans + sum / 3 << '\n';
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

D. Unique Palindromes(算贡献、构造)

题意:定义f(s,x)=c,表示在s的长度为x的前缀子串内本质不同的回文串有c个,现在给出一组c和x,让你构造出这样的字符串,如果不存在就输出NO。
思路:我们可以发现每增加一个字符最多增加一种新的回文串
(怎么发现啊喂!其实是这样的,对于一个字符串xxxxxxc,c所带来的新的回文串如果多于一个,那么我们可以找到两个回文串,xxxxxxc,xxxxxxc,放在一起,x[xxxx[xc]],我们可以对称回去,x[[xc]xxxx],所以较小的那个必定已经出现过了,马拉车(manacher)思想)
,所以不可能的情况就是产生了过多的新的本质不同的回文串。
对于长度为1的情况就一种。
对于长度为2的情况可以是两个不同的字符,也可以相同
对于长度大等于3的情况下,不管怎么安排我们都必定有三以上的本质不同回文串,对于大于等于三的情况,我们考虑在abcabcabcabcabc中插入连续相同的字符,abcabcabc相互之间不会产生回文,每一段考虑xxxxabcabcxxabcacxxabc这样的结构,加入的abc不会产生额外的贡献单个字符必定贡献一个。这样保证区间贡献回文数,连续的单个字符数,注意第一个特殊,因为这里abc有贡献。

#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define eps 1e-9
using namespace std;
const int N = 2e5 + 5;
int x[N], c[N];
void solve() {
	int n, k;
	cin >> n >> k;
	for (int i = 0; i < k; i++) cin >> x[i];
	for (int i = 0; i < k; i++) cin >> c[i];
	string ans;
	char block = 'a';
	if (c[0] > x[0]) {
		cout << "NO\n";
		return;
	}
	for (int i = 0; i < c[0] - 3; i++) ans += 'a';
	for (int i = c[0] - 3; i < x[0]; i++) {
		ans += block++;
		if (block == 'd') block = 'a'; 
	}
	for (int i = 1; i < k; i++) {
		int dc = c[i] - c[i - 1];
		int dx = x[i] - x[i - 1];
		if (dc > dx) {
			cout << "NO\n";
			return;
		}
		for (int j = 0; j < dc; j++) ans += 'c' + i;
		for (int j = dc; j < dx; j++) {
			ans += block;
			block++;
			if (block == 'd') block = 'a';
		}
	}
	cout << "YES\n";
	cout << ans << '\n';
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值