字符串问题模板 长期更新

来源:互联网 发布:app 开发 编程语言 编辑:程序博客网 时间:2024/05/01 22:58


后缀数组


#include<iostream>  #include<cstdio>  #include<cstring>  #include<algorithm>  using namespace std;  const int maxn = 1e5+5;  int t1[maxn], t2[maxn], c[maxn]; //c 基数排序辅助数组// int ra[maxn], height[maxn]; //rank数组,高度数组 int sa[maxn];  //suffix array  char str[maxn];  int n;    bool cmp(int *r, int a, int b, int l)  {      return r[a]==r[b]&&r[a+l]==r[b+l];  }    void da(char str[], int sa[], int ra[], int height[], int n, int m)  {      n++;      int i, j, p, *x = t1, *y = t2;      for(i = 0; i < m; i++) c[i] = 0;      for(i = 0; i < n; i++) c[x[i]=str[i]]++;      for(i = 1; i < m; i++) c[i] += c[i-1];      for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;      for(j = 1; j <= n; j<<=1)      {          p = 0;          for(i = n-j; i < n; i++) y[p++] = i;          for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i]-j;          for(i = 0; i < m; i++) c[i] = 0;          for(i = 0; i < n; i++) c[x[y[i]]]++;          for(i = 1; i < m; i++) c[i] += c[i-1];          for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];          swap(x, y);          p = 1; x[sa[0]] = 0;          for(i = 1; i < n; i++)              x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;          if(p >= n) break;          m = p;      }      int k = 0;      n--;      for(i = 0; i <= n; i++) ra[sa[i]] = i;      for(i = 0; i < n; i++)      {          if(k) k--;          j = sa[ra[i]-1];          while(str[i+k]==str[j+k]) k++;          height[ra[i]] = k;      }  }    int main(void)  {      while(~scanf(" %s", str))      {          n = strlen(str);          da(str, sa, ra, height, n, maxn);          for(int i = 1; i <= n; i++)              printf("%d%c", sa[i]+1, i==n ? '\n' : ' ');          for(int i = 2; i <= n; i++)              printf("%d%c", height[i], i==n ? '\n' : ' ');      }      return 0;  }  



字典树

(基本操作就是插入和查询,求以某一个字符串为前缀的单词的数量)



指针(动态模板)

#include<iostream>#include<cstdio>#include<cstring>using namespace std;typedef long long ll;const int mod=1e9+7;const int maxn=1e5+10;struct Trie{Trie *next[26];//next是表示每层有多少种类的数,如果只是小写字母,则26即可,  //若改为大小写字母,则是52,若再加上数字,则是62了,这里根据题意来确定。 int num;//num可以表示一个字典树到此有多少相同前缀的数目,这里根据需要应当学会自由变化。Trie(){int i;for(int i=0;i<26;i++)next[i]=NULL;num=0; } }root;void insert(char s[])//将字符串s插入到字典树中{Trie *p=&root;int i;for(int i=0;s[i];i++)//遍历s的每一个字符 {if(p->next[s[i]-'a']==NULL) //如果没有该字符对应的节点 p->next[s[i]-'a']=new Trie;p=p->next[s[i]-'a'];p->num++; } } int find(char s[])//返回以字符串s为前缀的单词的数量{Trie *p=&root;int i;for(int i=0;s[i];i++)//在字典树找到该单词的结尾位置{if(p->next[s[i]-'a']==NULL)return 0;p=p->next[s[i]-'a']; }return p->num;}int main(){char s[20];while(gets(s)){if(strlen(s)==0||s[0]==NULL)break;insert(s);}while(~scanf("%s",s)){printf("%d\n",find(s));}return 0;}

静态模板


#include<iostream>#include<cstdio>#include<cstring>#include<cmath> using namespace std;typedef long long ll;const int mod=1e9+7;const int maxn=1e6+10;int trie[maxn][26];//数组形式定义字典树,值存储的是下一个字符的位置int num[maxn]={0};//附加值,以某一字符串为前缀的单词的数量 int pos=1; void insert(char s[])//在字典树中插入单词s{int c=0;for(int i=0;s[i];i++){int n=s[i]-'a';if(trie[c][n]==0)//如果对应字符还没有值trie[c][n]=pos++;c=trie[c][n];num[c]++;  } } int find(char s[])//返回以某个字符串为前缀的单词的数量{int c=0;for(int i=0;s[i];i++){int n=s[i]-'a';if(trie[c][n]==0)return 0;c=trie[c][n]; }  return num[c];} int main(){char s[20];while(gets(s)){if(strlen(s)==0||s[0]==NULL)break;insert(s);}while(~scanf("%s",s)){printf("%d\n",find(s));}return 0;}



01trie

#include<iostream>  #include<cstdio>  #include<cstring>  #include<cmath>   using namespace std;  typedef long long ll;  const int mod=1e9+7;  const int maxn=6e6+10;const int N=3e5+10;  int trie[maxn][5];int num[maxn];  int vis[2*N];int pos=1;   int now;char str[25];void insert(char s[],int val)  {      int c=0;      int len = strlen(s);    for(int i=0;i < len;i++)      {          int bt=s[i]-'0';          if(trie[c][bt]==0)             {              num[pos] = 0;              memset(trie[pos],0,sizeof trie[pos]);  trie[c][bt]=pos++;}        c=trie[c][bt];      }    num[c] = val;    return ;}   int find(char s[])  {      int c=0;      int len = strlen(s);    for(int i=0;i < len;i++)      {          int bt=s[i]-'0';          if(trie[c][bt])          c=trie[c][bt];        else        c=trie[c][1-bt];     }        return num[c];  }   void change(int i){str[21]='\0';int tmp = i;for(int j = 20;j >= 0;j--){if(tmp){str[j] = tmp%2 +'0';tmp /= 2; }elsestr[j] = '0';}}int main(){      int n,m;  cin>>n>>m;     for(int i = 1;i <= n;i++){int a;scanf("%d",&a);if(vis[a]==0)vis[a] = 1;}for(int i = 0;i <= 600000 ;i++){if(vis[i] == 0){change(i);insert(str,i);}}now = 0;while(m--){int x;scanf("%d",&x);now ^= x;x = now;change(x);printf("%d\n",find(str)^now);}    return 0;  }  


字符串哈希


#include<bits/stdc++.h>using namespace std;typedef unsigned long long ull;const ull base=123;const int maxn=4e5+10;const int hashh= 1e6+10;char s[511][511];ull num[511*511],f[511][511];int n,m; struct hashmap{ull a[maxn];int head[hashh];int nxt[maxn];int siz;void init(){memset(head,-1,sizeof head);siz = 0;}bool find(ull val){int tmp = (val % hashh + hashh) % hashh;for(int i = head[tmp];i!=-1;i = nxt[i]){if(val == a[i]) return true;}return false;}void add(ull val){int tmp = (val % hashh + hashh) % hashh;if(find(val)) return ;a[siz] = val;nxt[siz] = head[tmp];//令next指向-1;head[tmp] = siz++; }}Hash;void init(){memset(f,0,sizeof f);num[0]=1;int cnt = 0;for(int i = 1; i <= n;i++) for(int j = 1;j <= m;j++) { cnt++; num[cnt] = num[cnt-1]*base; f[i][j] = f[i-1][j] + f[i][j-1] -f[i-1][j-1] + (s[i][j]-'0')*num[cnt]; } return ;}bool check(int x){Hash.init();for(int i = x;i <= n;i++) for(int j = x;j <= m;j++) { ull tmp = f[i][j] - f[i][j - x] - f[i - x][j] + f[i - x][j - x]; tmp = tmp * num[(n - i) * m + m - j]; if(Hash.find(tmp) == true) return true; Hash.add(tmp); } return false;}int main(){while(~scanf("%d %d",&n,&m)){for(int i = 1;i <= n;i++) scanf("%s",s[i]+1);init();int l = 1,r=min(n,m),mid,ans = -1;while(l<=r){mid = (l + r) >> 1;if(check(mid))l = mid + 1,ans = mid;elser = mid - 1;}printf("%d\n",ans);}return 0;}