被 自 己 蠢 哭 了 都 被自己蠢哭了都 被自己蠢哭了都
看 数 据 范 围 明 显 只 能 枚 举 两 个 字 符 串 看数据范围明显只能枚举两个字符串 看数据范围明显只能枚举两个字符串
可 以 根 据 枚 举 的 两 个 推 算 出 第 三 个 字 符 串 可以根据枚举的两个推算出第三个字符串 可以根据枚举的两个推算出第三个字符串
因 为 总 共 只 有 三 种 选 法 , 答 案 是 唯 一 的 因为总共只有三种选法,答案是唯一的 因为总共只有三种选法,答案是唯一的
至 于 判 断 第 三 个 字 符 串 是 否 存 在 至于判断第三个字符串是否存在 至于判断第三个字符串是否存在
s e t , m a p 或 者 转 化 为 数 字 都 可 以 啦 ! set,map或者转化为数字都可以啦! set,map或者转化为数字都可以啦!
代 码 里 是 用 的 字 典 树 代码里是用的字典树 代码里是用的字典树
#include <bits/stdc++.h>
using namespace std;
const int maxn=1509;
int tire[maxn*30][27],ans;
int n,m,top,isok[maxn*30];
string a[maxn];
void insert(string s)
{
int now=0;
for(int i=0,l=s.length();i<l;i++)
{
int k=s[i]-'A';
if(!tire[now][k]) tire[now][k]=++top;
now=tire[now][k];
}
isok[now]=1;
}
bool ask(string s)
{
int now=0;
for(int i=0,l=s.length();i<l;i++)
{
int k=s[i]-'A';
if(!tire[now][k]) return false;
now=tire[now][k];
}
return isok[now];
}
char find(char q,char w)
{
if(q!='S'&&w!='S') return 'S';
else if(q!='E'&&w!='E') return 'E';
else return 'T';
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i],insert(a[i]);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
string temp="";
for(int q=0;q<m;q++)
{
if(a[i][q]==a[j][q]) temp+=a[i][q];
else temp+=find(a[i][q],a[j][q]);
}
if(ask(temp)) ans++;
}
cout<<ans/3;
}