【BZOJ3555】企鹅QQ,第一次正确的使用哈希A题

来源:互联网 发布:软件网络就业前景 编辑:程序博客网 时间:2024/05/30 05:06

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);}
0 0