文章目录
传送门
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;
}