字符串hash

来源:互联网 发布:无锡华商网络骗局 编辑:程序博客网 时间:2024/05/17 01:39

大佬博客
题目链接
题意:刚开始给定n个字符串,每一个字符串有一个权值,后面有q次询问,1代表将a字符串的权值改为吧,2为询问有多少个字符串的后缀包含a并且权值是小于等于a字符串的权值的。
思路:上面大佬的博客里面讲了字符串的hash,这道题预处理处每一个字符串的hash值,然后n^2统计出任意两个字符串之间的后缀关系,最后用nq的复杂度查找就好了。

hash值储存在unsigned long long里面, 那样溢出时,会自动取余2的64次方

#include<cstdio>#include<vector>#include<cstring>#include<iostream>#include<algorithm>#define LL unsigned long longusing namespace std;const int maxn=1e6+10;struct zp{    char s[1010];    int w,len;} node[1010];LL p=131//取奇数质数 31 131;LL hash[1010][1010];//存每一个字符串所有前缀的hash值LL ha[maxn];void init(int n)//预处理每一个字符串的hash值{    ha[0]=1;    for(int i=1; i<=1010; i++)        ha[i]=ha[i-1]*p;    for(int i=1; i<=n; i++)    {        hash[i][0]=0;        for(int j=1; j<=node[i].len; j++)            hash[i][j]=hash[i][j-1]*p+node[i].s[j-1];    }}LL get_hash(int l,int r,int d)//得到d字符串l~r区间的hash值{    return hash[d][r]-hash[d][l-1]*ha[r-l+1];}vector<int> v[1010];int main(){    int ncase;    scanf("%d",&ncase);    while(ncase--)    {        int n;        scanf("%d",&n);        for(int i=1; i<=n; i++)        {            scanf("%s%d",node[i].s,&node[i].w);            v[i].clear();            node[i].len=strlen(node[i].s);        }        init(n);        for(int i=1;i<=n;i++)//n^2处理任意两个字符串之间的后缀关系        {            v[i].push_back(i);//v[i].push_back(j);代表第i个字符串是第j个字符串的后缀            for(int j=i+1;j<=n;j++)            {                if(node[i].len==node[j].len)                {                    if(get_hash(1,node[i].len,i)==get_hash(1,node[j].len,j))                        v[i].push_back(j),v[j].push_back(i);                }                else if(node[i].len>node[j].len)                {                    if(get_hash(node[i].len-node[j].len+1,node[i].len,i)==get_hash(1,node[j].len,j))                        v[j].push_back(i);                }                else if(node[i].len<node[j].len)                {                    if(get_hash(1,node[i].len,i)==get_hash(node[j].len-node[i].len+1,node[j].len,j))                        v[i].push_back(j);                }            }        }        int q;        scanf("%d",&q);        while(q--)//nq查询        {            int opt;            scanf("%d",&opt);            if(opt==1)            {                int a,b;                scanf("%d%d",&a,&b);                node[a].w=b;            }            else if(opt==2)            {                int a;                scanf("%d",&a);                int len=v[a].size(),ans=0;                for(int i=0;i<len;i++)                    if(node[v[a][i]].w<=node[a].w)                    ans++;                printf("%d\n",ans);            }        }    }}