目前只会做A,B,C后面尽量补上。
今年的实力离拿T还太远, 只能寄希望于明年了, sad。。
题目链接:GCJ|2014|Round1A
A:题意:给出n个01串, 每个字符串的长度为L, 现在可以同时可以对初始n个串的同一位置进行取反操作,问要操作多少次能达到目标串。
分析:小数据范围是:n,L <= 10, 联想到资格赛的C题(在我之前的blog出现过:资格赛C题)学到一种关于在n个数里快速求K个数组合的方式,我就开始枚举了。
太弱了写疵了,各种WA。。(想起前段时间的某次考试,一辈子的阴影么?) 最后还是找出了错误。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
int d[12];
int c[12];
int n, L;
bool gao(int *a, int n){
for(int i = 0; i < n; ++i){
if(a[i] != c[i])
return 0;
}
return 1;
}
int main(){
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
int T, cases = 1;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &L);
for(int i = 0; i < n; ++i){
char s[12];
scanf("%s", &s);
int tmp = 0;
for(int j = 0; j < L; ++j){
tmp = tmp*2 + s[j] - '0';
}
d[i] = tmp;
}
for(int i = 0; i < n; ++i){
char s[12];
scanf("%s", &s);
int tmp = 0;
for(int j = 0; j < L; ++j){
tmp = tmp*2 + s[j] - '0';
}
c[i] = tmp;
}
sort(d, d + n);
sort(c, c + n);
printf("Case #%d: ", cases++);
if(gao(d, n)){
printf("0\n");
continue;
}
int ans = 0;
for(int k = 1; k <= L; ++k){
int e[11];
for(int i = 0; i < n; ++i) e[i] = d[i];
int comb = (1 << k) - 1;
for(int i = 0; i < k; ++i){
for(int j = 0; j < n; ++j)
e[j] ^= (1 << (i));
}
while(comb < (1 << (L))){
sort(e, e + n);
if(gao(e, n)){
ans = k;
break;
}
int x = comb & -comb, y = comb + x;
comb = ((comb & ~y) / x >> 1) | y;
for(int i = 0; i < n; ++i) e[i] = d[i];
for(int i = 0; i < L; ++i){
for(int j = 0; j < n; ++j){
e[j] ^= (comb & (1 << i));
}
}
}
if(ans != 0) break;
}
if(ans != 0) printf("%d\n", ans);
else printf("NOT POSSIBLE\n");
}
return 0;
}
其实这题的正解是:枚举初始第一个串可以到达的目标串,这样可以求出对应的操作。根据操作去判断枚举是否合法即可, 时间复杂度为O(n^2*L)。对于大数据1 ≤ N ≤ 150,10 ≤ L ≤ 40,这样的复杂度也是能接受的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N = 210;
string x[210], y[210], z[210];
int main(){
int T, cases = 1;
scanf("%d", &T);
while(T--){
int n,m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
cin >> x[i];
for(int i = 1; i <= n; ++i)
cin >> y[i];
sort(y + 1, y + n + 1);
int flip[200], ans = -1;
for(int i = 1; i <= n; ++i){
memset(flip, 0, sizeof(flip));
int sum = 0;
for(int j = 0; j < m; j++){
if(y[i][j] != x[1][j]) flip[j] = 1;
sum += flip[j];
}
for(int j = 1; j <= n; ++j){
z[j] = "";
for(int k = 0; k < m; ++k){
if(flip[k])
z[j] += '0' + (!(x[j][k] - '0'));
else z[j] += x[j][k];
}
}
sort(z + 1, z + n + 1);
bool flag = true;
for(int j = 1; j <= n; ++j){
if(z[j] == y[j]) continue;
flag = 0;
break;
}
if(flag){
if(ans != -1)
ans = min(ans,sum);
else ans = sum;
}
}
if(ans == -1)
printf("Case #%d: NOT POSSIBLE\n", cases++);
else
printf("Case #%d: %d\n",cases++, ans);
}
return 0;
}