Time:2016.08.17
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
夏令营时做的题,一直没发题解
比较简单的思路是枚举每一位,然后看去掉这一位后有多少相同的串
关键是怎么快速比较与计算相同的串
比较容易的方法就是hash
hash值可以快速比较大小,而且通过对hash值
O(nlogn)
的排序后可以
O(n)
扫出相同的串
num[i][j]表示字符j在一个串中处于i位置时的hash值
hash[i]表示串i的hash值
枚举每一位j时,此时串i的hash值就是hash[i]-num[i][s[j]]
排序比较一下就可以了
复杂度
O(Lnlogn)
L是字符串长度
注意:
hash的方法是关键
这里直接使用131+自然溢出就好了
如果用什么取模大质数……会TLE or WA
当时搞的快疯了……
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
ll ans;
int n,len,S;
ull hash[30002],num[202][65],p[202],tmp[30002];
char s[30002][202];
int cal(char c)
{
if (c>='0'&&c<='9') return c-47;
else if (c>='A'&&c<='Z') return c-54;
else if (c>='a'&&c<='z') return c-60;
else if (c=='@') return 63;
else if (c=='_') return 64;
return 0;
}
main()
{
scanf("%d%d%d",&n,&len,&S);
p[0]=1;
for (int i=1;i<=len;i++) p[i]=p[i-1]*67*131;
for (int i=1;i<=len;i++)
for (int j=1;j<=64;j++)
num[i][j]=p[i-1]*j*131;
for (int i=1;i<=n;i++)
{
getchar();
for (int j=1;j<=len;j++)
s[i][j]=getchar(),
hash[i]=hash[i]+num[j][cal(s[i][j])];
}
for (int i=1;i<=len;i++)
{
for (int j=1;j<=n;j++) tmp[j]=hash[j]-num[i][cal(s[j][i])];
sort(tmp+1,tmp+n+1);
int sum=1;
for (int j=1;j<=n;j++)
if (tmp[j]!=tmp[j+1]) ans+=(ll)sum*(sum-1)/2,sum=1;
else sum++;
}
printf("%lld",ans);
}