A. Maximize the Last Element
题目大意
从奇数个元素中,每次可以删除相邻的两个,然后组合到一起,求剩下的数的最大值可能为多少。
思路
奇数位置可以被取到,偶数不可以。因为偶数位置两次有奇数个数没法全部消除。
代码实现
void solve() {
ll n; cin >> n;
ll ans = 0;
for (int i = 1; i <= n; i++) {
ll x; cin >> x;
if (i % 2) {
ans = max(ans, x);
}
}
cout << ans << "\n";
}
B. AND Reconstruction
题目大意
给定组数B,要求构造数组A,满足Bi=Ai+1&Ai。
思路
若当前B在二进制下的某一个位置为1的时候,对应的i和i+1号位置上二级进制对应也必须为1才能满足条件。
我们按此构造后,再检验一遍即可。
代码实现
void solve() {
ll n; cin >> n;
vector<ll>o(n);
for (int i = 0; i < n-1; i++)cin >> o[i];
vector<vector<ll>>need(n, vector<ll>(32));
vector<ll>num(n);
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j <= 30; j++) {
ll q = pow(2, j);
if (q & o[i]) {
need[i][j]++;
need[i + 1][j]++;
}
if (need[i][j]) {
num[i] += q;
}
}
}
for (int j = 0; j <= 30; j++) {
ll q = pow(2, j);
if (need[n-1][j]) {
num[n-1] += q;
}
}
for (int i = 0; i < n - 1; i++) {
if ((num[i] & num[i + 1]) != o[i]) {
cout << "-1\n";
return;
}
}
for (int i = 0; i < n; i++)cout << num[i] << " ";
cout << "\n";
}
C. Absolute Zero
题目大意
给定一数组,要求我们进行最多40次操作,每次选取一个数X,让所有数等于与X相减的绝对值,问是否存在操作序列满足让最终所有数均为0。
思路
每次减ceil((最大值+最小值)/2)即可。
(很抱歉没有证明,证明不好证,但是感觉这个思路很明显,小时候没事的时候这样玩过。)
代码实现
void solve() {
ll n; cin >> n;
vector<ll>o(n);
for (int i = 0; i < n; i++)cin >> o[i];
vector<ll>d;
ll cnt = 0;
while (d.size()!=40) {
sort(o.begin(), o.end());
ll mid = ceil((o[0] + o.back()) / 2.0);
d.push_back(mid);
for (int i = 0; i < n; i++) {
o[i] = abs(o[i] - mid);
}
}
for (int i = 0; i < n; i++) {
if (o[i] != 0) {
cout << "-1\n"; return;
}
}
cout << "40\n";
for (auto c : d)cout << c << " ";
cout << "\n";
}
D. Prime XOR Coloring
题目大意
图中存在n个点,编号从1-n,当满足u^v为质数的时候,u、v存在边。问用最少颜色给图中所有点染色,使得由边直接连接的两个顶点没有相同的颜色。
思路
首先考虑颜色,对于图来说,存在四色定理,及如果在平面上割出一些邻接的有限区域,那么可以用四种颜色来给这些区域染色,使得每两个邻接区域染的颜色都不一样。对图来说,我们可以将边看作是这些区域。
对于哪些边存在,我们考虑到,所有的质数都是奇数,所以偶数之间的异或均不存在边,奇数与奇数间也不存在边。暴力跑记录即可。
void solve() {
ll n;
cin >> n;
if (n <= 5) {
ll a[] = {1, 2, 2, 3, 3 };
set<ll>b;
for (int i = 0; i < n; i++) {
b.insert(a[i]);
}
cout << b.size() << endl;
for (int i = 0; i < n; i++) {
cout << a[i] << " ";
}
cout << endl;
return;
}
cout << 4 << endl;
vector<ll>a(n + 5), b(n + 5);
for (int i = 1; i <= n; i++) {
if (a[i] == 1)continue;
a[i] = 1;
a[i ^ 2] = 1;
if (i % 2 == 0) {
b[i] = 2;
}
else {
b[i] = 1;
}
if ((i ^ 2) % 2 == 0) {
b[i ^ 2] = 3;
}
else {
b[i ^ 2] = 4;
}
}
for (int i = 1; i <= n; i++) {
cout << b[i] << " ";
}
cout << endl;
}
E. Coloring Game
题目大意
交互题。
给定N个顶点和M条边。游戏共1、2、3三种颜色。每次游戏,Alice先选择其中两种颜色,然后Bob选择其中一个颜色,和图中未被染色的一个点进行染色。若最终图有相邻的点颜色相同,则Alice获胜,否则Bob获胜。
问是否可以选择一个人,并且选择一个操作可以确保胜利。
思路
对于Alice的必胜情况,必须满足图中存在基环,因为存在基环,Bob无论怎么选,总会有相同颜色的在一起。
对于Bob,如果不存在基环,我们必然可以通过选择颜色将图分开。
细节上来说,我们只需要判断图形是否为二分图,即可判断出是否存在基环。对于不存在基环的情况,我们就可以通过二分图的染色情况进行染色。
代码实现
ll color[210000]; // 两种颜色 -1 or 1
bool v[210000]; //当前点是否访问
vector<ll>node[210000]; //邻接矩阵
bool check(ll now, ll col) {
v[now] = true; color[now] = col; //访问当前节点 当前节点染色
bool ok = true; //check
for (auto x : node[now]) { //遍历相邻节点,在二分图中相邻节点中,必然颜色不同
if (v[x] == 0)ok &= check(x, -col); //未访问的进行染色
else ok &= (color[now] != color[x]); //若访问过则进行颜色判断
}
return ok;
}
void solve() {
ll n, m; cin >> n >> m;
for (ll i = 1; i <= n; i++) {
v[i] = false;
color[i] = 0;
node[i].clear();
}
bool f = false;
for (ll i = 0; i < m; i++) {
int x, y;
scanf("%d%d", &x, &y);
node[x].push_back(y);
node[y].push_back(x);
}
f = check(1, -1);
if (f == false) {
printf("Alice\n");
fflush(stdout);
for (int i = 1; i <= n; i++) {
printf("1 2\n");
fflush(stdout);
int l, r;
scanf("%d%d", &l, &r);
}
}
else {
queue<ll>a;
queue<ll>b;
for (int i = 1; i <= n; i++) {
if (color[i]==-1)a.push(i);
else b.push(i);
}
printf("Bob\n");
fflush(stdout);
for (int i = 1; i <= n; i++) {
int l, r;
scanf("%d%d", &l, &r);
if ((l == 1 || r == 1) && a.size()) {
printf("%d %d\n", a.front(), 1);
fflush(stdout);
a.pop();
continue;
}
if ((l == 2 || r == 2) && b.size()) {
printf("%d %d\n", b.front(), 2);
fflush(stdout);
b.pop();
continue;
}
if (a.size()) {
if(l==1||r==1)
printf("%d %d\n", a.front(), 1);
else
printf("%d %d\n", a.front(), 3);
fflush(stdout);
a.pop();
}
else {
if (l == 2 || r == 2)
printf("%d %d\n", b.front(), 2);
else
printf("%d %d\n", b.front(), 3);
fflush(stdout);
b.pop();
}
}
}
}