AtCoder Beginner Contest 236 A-F
AtCoder Beginner Contest 236
今日vp
补题:EF
F是个线性基
A - chukodai
交换两个字符的位置
#include <bits/stdc++.h>
using namespace std;
int main () {
string s;
cin >> s;
int a, b;
cin >> a >> b;
a --, b --;
swap (s[a], s[b]);
cout << s;
}
B - Who is missing?
1-n的数字中只有1个数字出现3次,其余数字都出现四次
找出那个特殊的数字
#include <bits/stdc++.h>
using namespace std;
int main () {
int n;
cin >> n;
n = 4*n-1;
map <int, int> mp;
while (n --) {
int x;
cin >> x;
mp[x] ++;
}
for (auto i : mp) {
if (i.second == 3) {
cout << i.first << endl;
break;
}
}
}
C - Route Map
字符串Si如果在T中出现过就输出yes,否咋No
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
string a[N];
int main () {
int n, m;
cin >> n >> m;
set<string> b;
for (int i = 1; i <= n; i ++) cin >> a[i];
while (m --) {
string t;
cin >> t;
b.insert (t);
}
for (int i = 1; i <= n; i ++) {
if (b.count (a[i])) cout << "Yes\n";
else cout << "No\n";
}
}
D - Dance
2n个人两两配对,若i与j配对(i<j),则所得价值为\(A_{i,j}\) 求最终所有人配对之后的价值最大异或和
dfs枚举每一种组合可能
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 20;
int a[N][N], n, ans;
bool vis[N];
void dfs (int cnt, int sum) {
if (cnt == n/2) {
ans = max (sum, ans);
return ;
}
for (int i = 1; i <= n; i ++) {
if (vis[i]) continue;
for (int j = i+1; j <= n; j ++) {
if (vis[j]) continue;
vis[i] = vis[j] = true;
dfs (cnt + 1, sum ^ a[i][j]);
vis[i] = vis[j] = false;
}
break;
}
}
signed main () {
scanf ("%lld", &n);
n *= 2;
for (int i = 1; i < n; i ++)
for (int j = i+1; j <= n; j ++) {
scanf ("%lld", &a[i][j]);
a[j][i] = a[i][j];
}
dfs (0, 0);
cout << ans << endl;
}
E - Average and Median
给定数组a,要从a中选出一些数构成数组b,需要满足数组a中相邻的两个数至少有一个被选上。
问构造出的b的平均数和中位数的最大值。
二分答案 + dp(check)
具体如何check可看代码及下面注释
实数+整数二分
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const double eps = 1e-6;
int a[N], n;
bool check_mid (int mid) {
vector <int> b(n), f(n);
for (int i = 1; i <= n; i ++) b[i-1] = (a[i]>=mid?1:-1);
f[0] = b[0], f[1] = max(0, b[0]) + b[1];
for (int i = 2; i < n; i ++) {
f[i] = max (f[i-1], f[i-2]) + b[i];
}
return max (f[n-2], f[n-1]) > 0;
}
bool check_aver (double mid) {
vector <double> b(n), f(n);
for (int i = 1; i <= n; i ++) b[i-1] = a[i] - mid;
f[0] = b[0], f[1] = max(0.0, b[0]) + b[1];
for (int i = 2; i < n; i ++) {
f[i] = max (f[i-1], f[i-2]) + b[i];
}
return max (f[n-2], f[n-1]) >= 0.0;
}
void binary_mid () {
int l = 0, r = 1e9;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check_mid(mid)) l = mid;
else r = mid - 1;
}
cout << l << endl;
}
void binary_aver () {
double l = 0.0, r = 1e9;
while (abs(r-l) > eps) {
double mid = (l+r) / 2;
if (check_aver(mid)) l = mid;
else r = mid;
}
cout << fixed << setprecision(6) << l << endl;
}
int main () {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
binary_aver(), binary_mid();
}
//相邻两个必须要选一个,
//求最大平均数和中位数
//至少要选(n+1)/2个
//3 4 5 9 -> 5.25
//3 4 5 9 2 -> 4
//二分(实数+整数)答案+dp
//check1: b[i]=a[i]-mid;
//check2: b[i]=(a[i]>=mid?1:-1);
//dp: f[i]=max(f[i-1],f[i-2])+b[i];
//ans: max(f[n-1], f[n-2]);
F - Spices
题意:在集合S中选择一些数字进行异或和
可以得到1∼2^n−1之间的所有数字,求最小的花费。
分析:线性基模板,只要学习了原理就能会了,可以看看大佬的笔记
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> pii;
const int N = 20;
int c[N], n, m;
signed main () {
cin >> n;
m = 1 << n;
vector <pii> v;
for (int i = 1; i < m; i ++) {
int x;
cin >> x;
v.push_back ({x, i});
}
sort (v.begin(), v.end()); //按照花费从小到大排
int ans = 0;
vector <int> t(n+1, 0); //线性基
for (auto vi : v) {
int val = vi.first, x = vi.second;
for (int i = 0; i < n; i ++) {
if ((x >> i & 1) == 0) continue;
if (t[i] == 0) { //更新线性基
ans += val;
t[i] = x;
break;
}
else x ^= t[i];
}
}
cout << ans << endl;
}
//在集合S中选择一些数字进行异或和
//可以得到1∼2^n−1之间的所有数字,求最小的花费。
//线性基模板