坑点有点多的暴力题。
解题思路:
观察本题,可以发现其实所有的首尾相同的单词都是“等价的”,在本题的要求中,其实并不在乎中间的字母。
由此想到可以用一个二维桶来记录所有“相同的”单词,然后枚举四个顶点的单词并往里面填。
时间复杂度为 O ( 1 ) O(1) O(1) ,是常数级的,这一点另一篇题解写得有些问题。
正如开头所说,这题有很多坑点,现列举如下:
-
读词的顺序
原文中是这样说的:
水平单词只能从左往右读,竖直的单词只能从上往下读。四个角共用一个字母。
这就意味着在代码中必须严格数组的顺序。
-
“重复的词”
原文中写到:
一个方案中不允许有同一个单词,两个方案不同是指它们所构成的正方形至少有一个字母不同。
这也就意味着当有几条边中首位字母一样时会有词重复计算,这里可以用减去的方法来完善算法。
-
其他
在代码中提到
代码:
#include<cstring>
#include<cstdio>
using namespace std;
int h[30][30],n;
long long ans;
char a[100000];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",a);
h[a[0]-'A'][a[strlen(a)-1]-'A']++;
//注意是大写的
}
int k1,k2,k3,k4;
for(int i=0;i<26;i++){
for(int j=0;j<26;j++){
k1=h[i][j];h[i][j]--;
for(int k=0;k<26;k++){
k2=h[j][k];h[j][k]--;
for(int l=0;l<26;l++){
/*这里有一个大坑
读英文单词全都是从上往下,从左往右的
不可以写成(i,j)(j,k)(k,l)(l,i)
*/
k3=h[l][k];h[l][k]--;
k4=h[i][l];
ans+=k1*k2*k3*k4;
h[l][k]++;
}
h[j][k]++;
}
h[i][j]++;
}
}
printf("%lld\n",ans);
//注意long long
return 0;
}