BZOJ4796 [CERC2016] Key Knocking
BZOJ4796 [CERC2016] Key Knocking
一道人类智慧题,
显然是一道构造,
满满的CF味.
是我做不了的题
其实这个题并不难,
我们有一个长为 \(3n\) 的串,
需要让它的权值为 \(2n\) ,
我们最多操作 \(n\) 次,
所以我们期望每 \(3\) 个位置的贡献为 \(2\) .
于是我们每 \(3\) 个一组,
如果是 \(010\) 或者 \(101\) ,
那就不需要我们操作了,
如果是 \(011\) 或者 \(100\) ,
那我们就操作前两位,
如果是 \(110\) 或者 \(001\) ,
那我们就操作后两位,
如果是 \(000\) 或者 \(111\) ,
那我们就需要看前一位了,
如果前一位跟我们当前这三位的第一位相同,
那我们就操作前两位,
反之操作后两位.
然后就完啦!
是不是很简单呢?
code:
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 3e5 + 5;
int n, a[N], ans[N];
int opt[] = {1, 2, 0, 1, 0, 0, 0, 2, 2, 0, 0, 0, 1, 0, 2, 1};
void read(){
char ch = getchar();
while (isdigit(ch)){
a[++n] = ch ^ 48;
ch = getchar();
}
}
int main(){
read();
n /= 3;
for (int i = 0; i < n; i++){
int t, x = 3 * i;
t = (a[x] << 3) + (a[x + 1] << 2) + (a[x + 2] << 1) + a[x + 3];
if (opt[t]){
ans[++*ans] = x + opt[t];
a[x + opt[t]] ^= 1, a[x + opt[t] + 1] ^= 1;
}
}
printf("%d\n", *ans);
for (int i = 1; i <= *ans; i++) printf("%d ", ans[i]);
return 0;
}
其实下面这份代码的正确性更好一些...
虽然可能多做操作,
但是一定符合题目要求,
上面那份代码前三位如果特殊构造一下是可以卡掉的,
下面这个就不会,
但是由于BZOJ没有SPJ,
所以过不去.
code:
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 3e5 + 5;
int n, a[N], ans[N];
int opt[] = {1, 2, 0, 1, 1, 0, 2, 2, 2, 2, 0, 1, 1, 0, 2, 1};
void read(){
char ch = getchar();
while (isdigit(ch)){
a[++n] = ch ^ 48;
ch = getchar();
}
}
int main(){
read();
n /= 3;
for (int i = 1; i < n; i++){
int t, x = 3 * i;
t = (a[x] << 3) + (a[x + 1] << 2) + (a[x + 2] << 1) + a[x + 3];
if (opt[t]){
ans[++*ans] = x + opt[t];
a[x + opt[t]] ^= 1, a[x + opt[t] + 1] ^= 1;
}
}
int t = (a[1] << 3) + (a[2] << 2) + (a[3] << 1) + a[4];
if (t == 0 || t == 15) ans[++*ans] = 2;
if (t == 1 || t == 14) ans[++*ans] = 1;
printf("%d\n", *ans);
for (int i = 1; i <= *ans; i++) printf("%d ", ans[i]);
return 0;
}
看不见我看不见我看不见我