E. Almost Fault-Tolerant Database 暴力枚举 + 分类讨论 + 思维
题目大意:
给你 (n) 个单元,每一个单元是一个长度为 (m) 的序列,让你构造一个单元 (ans) ,满足 (ans) 这个单元和给定的 (n) 个单元的每一个单元最多有两个位置的数不一样,如果存在这个单元,输出 "Yes" 并输出这个单元,如果没有则输出 "No"
题解:
首先假设答案就是 第一个单元,然后和其他以一比对,进行分类讨论:
- 如果和其他最多不同 (dif<=2) 那么直接输出答案
- 如果 (dif>4) ,那么不可能构造出来
- 如果 (dif==3||dif==4) 则要暴力枚举,首先找到那个 (dif) 最大的位置,(假设我枚举改动 (dif) 最大的这个位置),其中至少有一个位置是要变成第一个单元的,然后如果 (dif==4) ,那么另一个位置也要和第一个单元相同,如果 (dif==3) ,那么就在后面比较的过程中寻找另一个要变化的位置,但是容易发现可以把 (dif==3) 和 (dif==4) 归在一类
这个题目其实发现任意两个单元最多只有4个是不一样的这个是很简单的,但是发现这个之后想到直接暴力枚举,如果 (dif==4) ,那么毫无疑问,直接暴力枚举两个相同即可。
但是 (dif==3) ,那么除了要有一个和第一个单元相同,还会有一个是不固定的答案,也就是一个变量,需要在后面比较的时候获得,这个需要注意!
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
vector<vector<int>>a;
int n,m;
vector<int> Diff(int x,int y){
vector<int>ans;
for(int i=0;i<m;i++){
if(a[x][i]!=a[y][i]) ans.push_back(i);
}
return ans;
}
bool check(vector<int>&tmp){
for(int i=0;i<n;i++){
int cnt = 0,pos = -1;
for(int j=0;j<m;j++){
if(a[i][j]!=tmp[j]) cnt++;
if(tmp[j]==-1) pos = j;
}
if(cnt>3) return false;
if(cnt==3){
if(pos!=-1) tmp[pos] = a[i][pos];
else return false;
}
}
return true;
}
void Print(vector<int>tmp){
printf("Yes
");
for(int i=0;i<tmp.size();i++) {
if(tmp[i]==-1) printf("1 ");
else printf("%d ",tmp[i]);
}
printf("
");
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
vector<int>v;
for(int j=0,x;j<m;j++){
scanf("%d",&x);
v.push_back(x);
}
a.push_back(v);
}
int mx_id = 0,dif = 0;
for(int i=1;i<n;i++){
int res = Diff(0,i).size();
if(res>dif) dif = res,mx_id = i;
}
if(dif<=2) Print(a[0]);
else if(dif>4) printf("No
");
else{
vector<int> now = Diff(0,mx_id);
for(int i=0;i<now.size();i++){
for(int j=i+1;j<now.size();j++){
vector<int>tmp = a[mx_id];
int x = now[i],y = now[j];
tmp[x] = -1,tmp[y] = a[0][y];
if(check(tmp)){
Print(tmp);
return 0;
}
tmp[x] = a[0][x],tmp[y] = -1;
if(check(tmp)){
Print(tmp);
return 0;
}
}
}
printf("No
");
}
}