题意
$FJ$ 有 $n$ 头有斑点和 $n$ 头没有斑点的牛。
他认为一头牛有没有斑点和它的基因有关,所以他获取了所有奶牛的基因。
这些基因以字符串的形式给出,字符串中只包含 $A,C,G,T$。
如果 $FJ$ 认为一头奶牛的基因的第 $i,j,k$ 个字符决定它有没有斑点,那么 $i,j,k$ 必须满足:
任意一头 有斑点的 牛的基因的第 $i,j,k$ 个字符没有一个有斑点的 牛与其重复。
求共有的多少个 符合规定 的 $i,j,k$。
举个例子1
斑点牛 :
- $ATG...$
- $ACG...$
- $AGT...$
无斑牛 :
- $ACC...$
- $ACC...$
- $ACC...$
可见 $1,2,3$ 号位可以判断牛有没有斑点,因为没有一头斑点牛的 $1,2,3$ 号基因在无斑牛中出现过。
举个例子2
斑点牛 :
- $ATG...$;
- $ACC...$;
- $AGT...$;
无斑牛 :
- $ACC...$;
- $ACC...$;
- $ACC...$;
可见 $1,2,3$ 号位不可以判断牛有没有斑点,因为有第 $2$ 头斑点牛的 $1,2,3$ 号基因在无斑牛中出现过。
思路
可以先从时间复杂度入手。
首先花 $O(m^3)$ 暴力枚举这三个位置,接下来的问题是如何在 $O(n)$ 的时间内判断。
可以先想想如何用 $O(n^2)$ 的时间判断。
对于多个字符串是否相同的判断,我们很容易想到哈希表。
先计算出每个斑点牛这三个位置的哈希值,再计算每个无斑牛的哈希值,看有没有相同的。
怎么优化呢?
我么可以定义两个哈希数组: hs,hp
,分别储存斑点牛和无斑牛。设 H
一个为有斑牛的哈希值。那么我们将 $hs_H$ 设为 true
。
设 h
为一个无斑牛的哈希值。则将 $hp_i$ 设为 h
。
那么我们如果想要判断第 $i$ 个无斑牛的哈希值是否在斑点牛中出现过。就可以使用表达式 $hs_{hp_i}$ 来判断。
最后贴上代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,ans;
char S[510][55],P[510][55];
int HashS[20000],HashP[20000];
bool B[55][55][55];
void hashS(int fir,int sec,int thi){
memset(HashS,0,sizeof(HashS));
for(int i=1;i<=n;i++){
int tmp=(S[i][fir]-'A'+1)+(S[i][sec]-'A'+1)*26+(S[i][thi]-'A'+1)*26*26;
HashS[tmp]=1;
}
return;
}
void hashP(int fir,int sec,int thi){
memset(HashP,0,sizeof(HashP));
for(int i=1;i<=n;i++){
int tmp=(P[i][fir]-'A'+1)+(P[i][sec]-'A'+1)*26+(P[i][thi]-'A'+1)*26*26;
HashP[i]=tmp;
}
return;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)cin>>S[i][j];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cin>>P[i][j];
}
int fir,sec,thi;
for(fir=1;fir<=m;fir++){
for(sec=fir+1;sec<=m;sec++){
for(thi=sec+1;thi<=m;thi++){
bool flag=0;
hashS(fir,sec,thi);
hashP(fir,sec,thi);
for(int i=1;i<=n;i++){
if(HashS[HashP[i]]){flag=1;break;}//哈希小技巧
}
if(flag)continue;
B[fir][sec][thi]=1;//记录答案
}
}
}
for(int i=1;i<=m;i++){//统计答案
for(int j=1;j<=m;j++){
for(int k=1;k<=m;k++){
if(B[i][j][k])ans++;
}
}
}
printf("%d",ans);
return 0;
}