• 蓝书2.1 哈希和哈希表


    T1 Power Strings    poj 2406

    题目大意:

    求每个字符串的最短循环节的循环次数

    思路:

    哈希用kmp做

    直接判断一下n-nxt[n]是否是n的约数

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<vector>
     8 #include<queue>
     9 #define inf 2139062143
    10 #define ll long long
    11 #define MAXN 100100100
    12 using namespace std;
    13 inline int read()
    14 {
    15     int x=0,f=1;char ch=getchar();
    16     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    17     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    18     return x*f;
    19 }
    20 int n,nxt[MAXN];
    21 char a[MAXN];
    22 int main()
    23 {
    24     while(scanf("%s",a+1))
    25     {
    26         if(a[1]=='.') break;
    27         n=strlen(a+1);
    28         for(int i=1,j=0;i<n;i++)
    29         {
    30             while(a[i+1]!=a[j+1]&&j) j=nxt[j];
    31             if(a[i+1]==a[j+1]) j++;
    32             nxt[i+1]=j;
    33         }
    34         if(n%(n-nxt[n])==0) printf("%d
    ",n/(n-nxt[n]));
    35         else puts("1");
    36     }
    37 }
    View Code

    T2 Seek the name ...  poj 2752

    题目大意:

    求每个字符串的所有border

    思路:

    用nxt[n]一直往前跳nxt就行了

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<vector>
     8 #include<queue>
     9 #define inf 2139062143
    10 #define ll long long
    11 #define MAXN 400100
    12 using namespace std;
    13 inline int read()
    14 {
    15     int x=0,f=1;char ch=getchar();
    16     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    17     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    18     return x*f;
    19 }
    20 int n,nxt[MAXN];
    21 char a[MAXN];
    22 void work(int x) {if(!x)return ;work(nxt[x]);printf("%d ",x);}
    23 int main()
    24 {
    25     while(scanf("%s",a+1)!=EOF)
    26     {
    27         n=strlen(a+1);
    28         for(int i=1,j=0;i<n;i++)
    29         {
    30             while(a[i+1]!=a[j+1]&&j) j=nxt[j];
    31             if(a[i+1]==a[j+1]) j++;
    32             nxt[i+1]=j;
    33         }
    34         work(n);puts("");
    35     }
    36 }
    View Code

    T3  friends bzoj 3916

    题目大意:

    字符串s复制一遍后加入一个字符x得到字符串t

    已知t 求s的个数

    思路:

    枚举插入的位置 字符串哈希判断

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<vector>
     8 #include<queue>
     9 #include<map>
    10 #define inf 2139062143
    11 #define ll long long
    12 #define MAXN 2000100
    13 const int MOD=1e9+7;
    14 using namespace std;
    15 inline int read()
    16 {
    17     int x=0,f=1;char ch=getchar();
    18     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    19     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    20     return x*f;
    21 }
    22 map <int,int> vis;
    23 int n,ans,t;
    24 ll hsh[MAXN],p[MAXN];
    25 char ch[MAXN];
    26 ll Minus(ll a,ll b) {return (a-b)%MOD>0?(a-b)%MOD:(a-b)%MOD+MOD;}
    27 int main()
    28 {
    29     n=read(),p[0]=1;
    30     scanf("%s",ch+1);
    31     if(!(n&1)) {puts("NOT POSSIBLE");return 0;}
    32     for(int i=1;i<=n;i++) p[i]=(p[i-1]*137)%MOD,hsh[i]=(ch[i]-'A'+1+hsh[i-1]*137%MOD)%MOD;
    33     for(int i=1,x,y;i<=n;i++)
    34     {
    35         if(i<=n/2+1) x=(hsh[i-1]*p[n/2-i+1]%MOD+Minus(hsh[n/2+1],hsh[i]*p[n/2+1-i]))%MOD,y=Minus(hsh[n],hsh[n/2+1]*p[n/2]);
    36         else x=hsh[n/2],y=(Minus(hsh[i-1],hsh[n/2]*p[i-n/2-1])*p[n-i]%MOD+Minus(hsh[n],hsh[i]*p[n-i]))%MOD;
    37         if(x==y&&!vis[x]) ans++,t=i,vis[x]=1;
    38     }
    39     if(!ans) puts("NOT POSSIBLE");
    40     else if(ans>1) puts("NOT UNIQUE");
    41     else if(t>=n/2+1) for(int i=1;i<=n/2;i++) printf("%c",ch[i]);
    42     else for(int i=n/2+2;i<=n;i++) printf("%c",ch[i]);
    43 }
    View Code

    T4 A Horrible Poem bzoj 2795

    题目大意:

    q次询问 每次询问字符串的一段子串的最短循环节

    思路:

    很容易想到 q sqrt(n) 枚举每段长度的所有约数 O1 判断

    但是感觉太捞了

    于是可以分解质因数 用线筛求出每个数最小的质因数

    不断枚举质因数 用长度判断

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<vector>
     8 #include<queue>
     9 #include<map>
    10 #define inf 2139062143
    11 #define ll long long
    12 #define MAXN 500100
    13 const int MOD=1e9+7;
    14 using namespace std;
    15 inline int read()
    16 {
    17     int x=0,f=1;char ch=getchar();
    18     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    19     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    20     return x*f;
    21 }
    22 ll Minus(ll a,ll b) {return (a-b)%MOD>0?(a-b)%MOD:(a-b)%MOD+MOD;}
    23 int n,T,ntp[MAXN],p[MAXN],cnt;
    24 char ch[MAXN];
    25 ll hsh[MAXN],pw[MAXN];
    26 void mem()
    27 {
    28     for(int i=2;i<MAXN;i++)
    29     {
    30         if(!ntp[i]) ntp[i]=i,p[++cnt]=i;
    31         for(int j=1;p[j]*i<MAXN;j++)
    32         {
    33             ntp[p[j]*i]=p[j];
    34             if(i%p[j]==0) break;
    35         }
    36     }
    37 }
    38 int main()
    39 {
    40     n=read(),pw[0]=1;int a,b,len;
    41     scanf("%s",ch+1);
    42     for(int i=1;i<=n;i++) pw[i]=(pw[i-1]*137)%MOD,hsh[i]=(ch[i]-'a'+1+hsh[i-1]*137%MOD)%MOD;
    43     T=read();mem();
    44     while(T--)
    45     {
    46         a=read(),b=read(),len=b-a+1;
    47         for(int i=len,c;i>1;)
    48         {
    49             c=ntp[i];
    50             while(len%c==0&&Minus(hsh[b-len/c],hsh[a-1]*pw[b-len/c-a+1])==Minus(hsh[b],hsh[a+len/c-1]*pw[b-a-len/c+1])) len/=c;
    51             while(i%c==0) i/=c;
    52         }
    53         printf("%d
    ",len);
    54     }
    55 }
    View Code

    T5 Beads bzoj 2081

    题目大意:

    求一些长度 使这些紧挨着的长度的子串有多少个不同的(前后翻转算一个)

    思路:

    暴力枚举长度 由调和级数可得总复杂度为 nlogn

    然后使用set 和哈希求出多少个不同的子串即可

    卡1e9+7 但没卡自然溢出是什么鬼

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<vector>
     8 #include<queue>
     9 #include<set>
    10 #define inf 2139062143
    11 #define ll long long
    12 #define MAXN 200100
    13 const int MOD=98754321;
    14 using namespace std;
    15 inline int read()
    16 {
    17     int x=0,f=1;char ch=getchar();
    18     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    19     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    20     return x*f;
    21 }
    22 set <int> s;
    23 int n,ans,ar[MAXN],cnt,g[MAXN],hsh[MAXN],HSH[MAXN],pw[MAXN];
    24 char ch[MAXN];
    25 void calc(int x)
    26 {
    27     s.clear();
    28     for(int i=1,a,b;i+x-1<=n;i+=x)
    29     {
    30         a=hsh[i+x-1]-hsh[i-1]*pw[x],b=HSH[i]-HSH[i+x]*pw[x];
    31         s.insert(min(a,b));
    32     }
    33     if(s.size()==ans) ar[++cnt]=x;
    34     if(s.size()>ans) ans=s.size(),ar[cnt=1]=x;
    35 }
    36 int main()
    37 {
    38     n=read();
    39     for(int i=pw[0]=1;i<=n;i++) g[i]=read(),pw[i]=pw[i-1]*19260817,hsh[i]=g[i]+hsh[i-1]*19260817;
    40     for(int i=n;i;i--) HSH[i]=g[i]+HSH[i+1]*19260817;
    41     for(int i=1;i<=n;i++) calc(i);
    42     printf("%d %d
    %d",ans,cnt,ar[1]);
    43     for(int i=2;i<=cnt;i++) printf(" %d",ar[i]);
    44 }
    View Code

    T6 Antisymmetry bzoj 2084

    题目大意:

    对一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串

    现在给出一个长度为N的01字符串,求它有多少个子串是反对称的

    思路:

    枚举每个中心

    然后二分长度 哈希判断 

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<vector>
     8 #include<queue>
     9 #include<set>
    10 #define inf 2139062143
    11 #define ll long long
    12 #define MAXN 500100
    13 const int MOD=1e9+7;
    14 const int bas=2333;
    15 using namespace std;
    16 inline int read()
    17 {
    18     int x=0,f=1;char ch=getchar();
    19     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    20     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    21     return x*f;
    22 }
    23 int n;
    24 ll hsh[MAXN],HSH[MAXN],pw[MAXN],ok[MAXN],ans;
    25 char ch[MAXN];
    26 int check(int pos,int x)
    27 {
    28     return ((hsh[pos+x]-hsh[pos-x]*pw[2*x]%MOD+MOD)%MOD+(HSH[pos-x+1]-HSH[pos+x+1]*pw[2*x]%MOD+MOD)%MOD)%MOD==ok[2*x];
    29 }
    30 int main()
    31 {
    32     n=read();scanf("%s",ch+1);
    33     for(int i=pw[0]=1;i<=n;i++) pw[i]=pw[i-1]*bas%MOD,hsh[i]=(ch[i]-'0'+hsh[i-1]*bas%MOD)%MOD,ok[i]=(1+ok[i-1]*bas%MOD)%MOD;
    34     for(int i=n;i;i--) HSH[i]=(ch[i]-'0'+HSH[i+1]*bas%MOD)%MOD;
    35     for(int i=1,l,r,mid,res;i<n;i++)
    36     {
    37         res=l=0,r=min(i,n-i);
    38         while(l<=r)
    39         {
    40             mid=(l+r)>>1;
    41             if(check(i,mid)) res=mid,l=mid+1;
    42             else r=mid-1;
    43         }
    44         ans+=res;
    45     }
    46     printf("%lld",ans);
    47 }
    View Code

    手写hash_table之类的还是算了吧 map就完事了

  • 相关阅读:
    HDU 6984
    洛谷 P6776
    C语言 error C4996: This function or variable may be unsafe
    C语言 sizeof 函数
    C语言 strlen 函数
    C语言 char 字符串
    C语言 goto 语句
    C语言 switch 语句
    C语言 do while 和 while 循环
    C语言 while 循环
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/9322368.html
Copyright © 2020-2023  润新知