Codeforces Round #761 (Div. 2)
Codeforces Round #761 (Div. 2)
A. Forbidden Subsequence
题意:给出一个串s和一个串t,要求出s字典序最小的排列使得不包含t作为subsequence,其中t为abc的排列
其实就是对abc三个字母进行排列使得不按t给出的顺序,如果t是abc就按acb其他都按abc,即所有字母按字母序给出
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int cnt[30];
signed main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int T;
cin >> T;
while (T--) {
for (int i = 0; i <= 26; ++i) cnt[i] = 0;
string s, t;
cin >> s >> t;
int sz = s.size();
for (int i = 0; i < sz; ++i) {
cnt[s[i] - 'a']++;
}
if (!cnt[0] || !cnt[1] || !cnt[2]) {
for (int i = 0; i < 26; ++i) {
for (int j = 0; j < cnt[i]; ++j) {
cout << (char) ('a' + i);
}
}
cout << endl;
continue;
}
for (int i = 0; i < cnt[0]; ++i) cout << 'a';
if (t == "abc") {
for (int i = 0; i < cnt[2]; ++i) cout << 'c';
for (int i = 0; i < cnt[1]; ++i) cout << 'b';
} else {
for (int i = 0; i < cnt[1]; ++i) cout << 'b';
for (int i = 0; i < cnt[2]; ++i) cout << 'c';
}
for (int i = 3; i < 26; ++i) {
for (int j = 0; j < cnt[i]; ++j) {
cout << (char) ('a' + i);
}
}
cout << endl;
}
}
B. GCD Problem
题意:给出n,要求三个不同的数abc使得 gcd ( a , b ) = c \gcd(a,b) = c gcd(a,b)=c。
设c= 1,一定可以找出两个数ab互质
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
signed main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
ll T;
cin >> T;
while (T--) {
ll n;
cin >> n;
n--;
if (n & 1) {
cout << 2 << " " << n - 2 << " " << 1 << endl;
continue;
}
if (n % 4 == 0) {
cout << n / 2 - 1 << " " << n / 2 + 1 << " " << 1 << endl;
} else cout << n / 2 - 2 << " " << n / 2 + 2 << " " << 1 << endl;
}
}
C. Paprika and Permutation
题意:给出一个长度为n的数列,每次操作为选一个i,使得 a i = a i m o d x a_i = a_i \mod x ai=aimodx,其中每次操作的ix都可以重新任选,要求最少的操作使得操作完的数列为1到n的排列,或声明不存在
将在1-n范围中能用的数先去掉,剩下的数从大到小排序,对应要求的1-n也从大到小排序依次去看他能不能操作
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
vector<int> a, b;
bool vis[N];
signed main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
ll T;
cin >> T;
while (T--) {
ll n;
cin >> n;
for (int i = 1; i <= n; ++i) vis[i] = 0;
a.clear(), b.clear();
for (int i = 1, x; i <= n; ++i) {
cin >> x;
if (x <= n && !vis[x]) {
vis[x] = 1;
} else {
a.push_back(x);
}
}
sort(a.begin(), a.end(), [&](int x, int y) { return x > y; });
for (int i = n; i >= 1; i--) {
if (!vis[i]) {
b.push_back(i);
}
}
bool flag = 1;
int siz = a.size();
for (int i = 0; i < siz; ++i) {
if (a[i] <= b[i] * 2){
flag = 0;
break;
}
}
if(flag) cout << a.size() << endl;
else cout << -1 << endl;
}
}
D1. Too Many Impostors (easy version)
题意:交互题,有n个人(n为3的倍数),其中有k个是骗子,其余为普通人,每次可以任选三个人,回答给出这三个人中是骗子多还是普通人多,2n次询问内给出所有骗子的位置,保证 1 3 < k < 2 3 \frac{1}{3} < k < \frac{2}{3} 31<k<32
相当于n个球,k个白球,剩下为黑球…
如果能找出一个黑球一个白球,接下来只要O(n)询问就可以得出其余球的状况,由于题给n为3的倍数,将每三个划分为一组,依次询问,找出一组黑球多的一组白球多的,(因为k的范围所以一定可以找出这样的两组
只考虑这两组六个球,对于每组的头拿出来,通过对剩余四个位置的综合询问可以得出这两个球的状态,调整找出一黑一白两个球,
这种做法大概是 O ( 4 3 n ) O(\frac{4}{3}n) O(34n)次询问
#include <bits/stdc++.h>
using namespace std;
vector<int> vec;
signed main() {
int T;
cin >> T;
while (T--) {
vec.clear();
int n;
cin >> n;
int blackpos, whitepos;
int black;
for (int i = 1; i <= n; i += 3) {
cout << "? " << i << " " << i + 1 << " " << i + 2 << endl;
int x;
cin >> x;
if (x == 1) {
blackpos = i;
} else {
whitepos = i;
}
}
int cnt0 = 0, cnt1 = 0;
vector<int> qe;
qe.clear();
qe.push_back(blackpos + 1);
qe.push_back(blackpos + 2);
qe.push_back(whitepos + 1);
qe.push_back(whitepos + 2);
int sz = qe.size();
for (int i = 0, x; i < sz; ++i) {
cout << "? " << blackpos << " " << whitepos << " " << qe[i] << endl;
cin >> x;
if (x == 0) {
cnt0++;
vec.push_back(qe[i]);
} else {
cnt1++;
black = qe[i];
}
}
if (cnt1 == 4) { // 2black //
vec.clear();
whitepos++;
vec.push_back(whitepos);
for (int i = 1, x; i <= n; ++i) {
if (i == blackpos || i == whitepos - 1 || i == whitepos) continue;
cout << "? " << blackpos << " " << whitepos << " " << i << endl;
cin >> x;
if (x == 0) vec.push_back(i);
}
} else if (cnt0 == 4) { //2white //
vec.clear();
vec.push_back(blackpos);
vec.push_back(whitepos);
blackpos++;
for (int i = 1, x; i <= n; ++i) {
if (i == blackpos - 1 || i == blackpos || i == whitepos) continue;
cout << "? " << blackpos << " " << whitepos << " " << i << endl;
cin >> x;
if (x == 0) vec.push_back(i);
}
} else { //1 black 1white //
for (int i = 1, x; i <= n; ++i) {
if ((blackpos <= i && i <= blackpos + 2) || (whitepos <= i && i <= whitepos + 2)) continue;
cout << "? " << blackpos << " " << whitepos << " " << i << endl;
cin >> x;
if (x == 0) vec.push_back(i);
else black = i;
}
cout << "? " << black << " " << vec[vec.size() - 1] << " " << blackpos << endl;
int x;
cin >> x;
if (x == 1) vec.push_back(whitepos);
else vec.push_back(blackpos);
}
cout << "! " << endl;
int res = vec.size();
cout << res << " ";
for (int i = 0; i < res; ++i) {
cout << vec[i] << " ";
}
cout << endl;
}
}
D2. Too Many Impostors (hard version)
题意与D1一致,询问次数限制变为n+6.
官方题解大概是n+3左右
分组和D1思路一致,这里用
n
3
\frac{n}{3}
3n,取出一个0组一个1组,标号abcdef,分别对abc,bcd,cde,def询问,其中abc/def之前询问过,额外+2次,找出一黑一白
每组用2的代价确定三个的01值
当一个组确定为0组或1组的时候,他的排布一共就只有4种,每次询问减少一半的情况
假设询问0组,标号i,j, k ,用1去配合 问1 i,j,如果01,则k为0,在用01,i询问得出i,推出j;
后排给个n+1的思路:
谢谢@hoshimi同学(嗯嗯嗯对对对,直接cv了,讲得挺清楚的
0组abc,1组def
问abd和abe,如果都是0,说明ab都是0,再问ade和aef,如果00则def101,01则def011,10则def110,然后找个0和1检验c,这样是2组7次
如果abd和abe是01之类的就知道def是什么了,再用其中的1检验abc(和a检验def同理)
然后同理检验别的组
代码先咕