字符串入门

暴力

hdu1617

http://acm.hdu.edu.cn/showproblem.php?pid=1671

给定字符串集合S,问是否有字符串i,j属于S并且i为j的前缀

字典树,构造时insert的时候直接返回是否触犯这个规则,标记两种,

一种是1,表示这条路曾经有字符串走过,一种是2,表示这个点是一个字符串的结尾,这样就可以了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<functional>
 6 #include<iostream>
 7 #include<cmath>
 8 #include<string>
 9 #include<cctype>
10 #include<stack>
11 #include<set>
12 #include<map>
13 #include<ctime>
14 using namespace std;
15 #define For(i,n) for(int i=1;i<=n;i++)
16 #define Fork(i,k,n) for(int i=k;i<=n;i++)
17 #define Rep(i,n) for(int i=0;i<n;i++)
18 #define ForD(i,n) for(int i=n;i;i--)
19 #define RepD(i,n) for(int i=n;i>=0;i--)
20 #define Forp(x) for(int p=pre[x];p;p=next[p])
21 #define Lson (x<<1)
22 #define Rson ((x<<1)+1)
23 #define MEM(a) memset(a,0,sizeof(a));
24 #define NEG(a) memset(a,-1,sizeof(a));
25 #define INF 0x3f3f3f3f
26 #define LLINF 0x3f3f3f3f3f3f3f3f
27 #define MAXN 500000
28 #define ll long long
29 int t[MAXN][11];
30 int sz,s[MAXN];
31 int insert(char ch[])
32 {
33     int flg=1;
34     int k,len=strlen(ch),now=0;
35     Rep(p,len)
36     {
37         k=ch[p]-'0';
38         if(t[now][k]==0) t[now][k]=++sz;
39         now=t[now][k];
40         if((s[now]==1&&p==len-1)||s[now]==2)
41         {
42             flg=0;
43         }
44         //printf("now=%d\n",now);
45         s[now]=1;
46     }
47     s[now]=2;
48     return flg;
49 }
50 int main()
51 {
52     int T;
53     scanf("%d",&T);
54     while(T--){
55         sz=0;
56         MEM(s);
57         MEM(t);
58         char buf[2000];
59         int flg=1;
60         int n;
61         scanf("%d",&n);
62         while(n--)
63         {
64             scanf("%s",buf);
65             flg&=insert(buf);
66             //if(flg==0) printf("buf=%s\n",buf);
67         }
68         printf(flg==1?"YES\n":"NO\n");
69     }
70 
71 }
View Code

 

hdu1247

http://acm.hdu.edu.cn/showproblem.php?pid=1671

稍微开始加难点,给定字符串集合S,问S内是否有两个单词构成另外一个单词 

字典树,先完成trie,然后再次讨论每一个字符串i,若i在ask时遇到一个字符串end标记,

就从这里开始到i结尾作为一个字符串去trie树中查询是否存在

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<functional>
 6 #include<iostream>
 7 #include<cmath>
 8 #include<string>
 9 #include<vector>
10 #include<cctype>
11 #include<stack>
12 #include<set>
13 #include<map>
14 #include<ctime>
15 using namespace std;
16 #define For(i,n) for(int i=1;i<=n;i++)
17 #define Fork(i,k,n) for(int i=k;i<=n;i++)
18 #define Rep(i,n) for(int i=0;i<n;i++)
19 #define ForD(i,n) for(int i=n;i;i--)
20 #define RepD(i,n) for(int i=n;i>=0;i--)
21 #define Forp(x) for(int p=pre[x];p;p=next[p])
22 #define Lson (x<<1)
23 #define Rson ((x<<1)+1)
24 #define MEM(a) memset(a,0,sizeof(a));
25 #define NEG(a) memset(a,-1,sizeof(a));
26 #define INF 0x3f3f3f3f
27 #define LLINF 0x3f3f3f3f3f3f3f3f
28 #define MAXN 500000
29 #define ll long long
30 int t[MAXN][26];
31 int sz,s[MAXN];
32 void insert(char ch[])
33 {
34     int k,len=strlen(ch),now=0;
35     Rep(p,len)
36     {
37         k=ch[p]-'0';
38         if(t[now][k]==0) t[now][k]=++sz;
39         now=t[now][k];
40     }
41     s[now]=1;
42 }
43 char buf[500000][50];
44 int nume;
45 vector<string>ans;
46 int get(char ch[])
47 {
48     int len=strlen(ch),k,now=0;
49     Rep(p,len)
50     {
51         k=ch[p]-'0';
52         if(t[now][k]==0) return 0;
53         now=t[now][k];
54     }
55     return s[now];
56 }
57 void ask(char ch[])
58 {
59     int len=strlen(ch),k,now=0;
60     Rep(p,len)
61     {
62         k=ch[p]-'0';
63         if(s[now]==1&&get(ch+p)==1)
64         {
65             string tmp(ch);
66             ans.push_back(tmp);
67             return;
68         }
69         now=t[now][k];
70     }
71 }
72 int main()
73 {
74     //freopen("in.txt","in",stdin);
75     while(gets(buf[nume])&&buf[nume][0]!=0)
76     {
77         insert(buf[nume]);
78         //printf("buf=%s\n",buf[nume]);
79         nume++;
80         //printf("nume=%d\n",nume);
81     }
82     Rep(i,nume)
83     {
84         //printf("%s\n",buf[i]);
85         ask(buf[i]);
86     }
87     sort(ans.begin(),ans.end());
88     sz=ans.size();
89     Rep(i,sz)
90     {
91         cout<<ans[i]<<endl;
92     }
93     return 0;
94 }
View Code

 

hdu4099

http://acm.hdu.edu.cn/showproblem.php?pid=4099

10w以内的斐波那契数作为集合S,问一个不超过长度40的数字i是否是某一个S内的数字j的前缀,

如果是求符合的j的最小下标

字典树,insert所有的斐波,但是显然开不下那么大的,注意到40的范围,所以insert的时候只留下40长度,

开800w数组。同时为了方便后来的查询,每当字典树开新节点的时候标记下标。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<algorithm>
  5 #include<functional>
  6 #include<iostream>
  7 #include<cmath>
  8 #include<string>
  9 #include<vector>
 10 #include<cctype>
 11 #include<stack>
 12 #include<set>
 13 #include<map>
 14 #include<ctime>
 15 using namespace std;
 16 #define For(i,n) for(int i=1;i<=n;i++)
 17 #define Fork(i,k,n) for(int i=k;i<=n;i++)
 18 #define Rep(i,n) for(int i=0;i<n;i++)
 19 #define ForD(i,n) for(int i=n;i;i--)
 20 #define RepD(i,n) for(int i=n;i>=0;i--)
 21 #define Forp(x) for(int p=pre[x];p;p=next[p])
 22 #define Lson (x<<1)
 23 #define Rson ((x<<1)+1)
 24 #define MEM(a) memset(a,0,sizeof(a));
 25 #define NEG(a) memset(a,-1,sizeof(a));
 26 #define INF 0x3f3f3f3f
 27 #define LLINF 0x3f3f3f3f3f3f3f3f
 28 #define MAXN 8000000
 29 #define ll long long
 30 #define out(name,a) cout<<name<<"="<<a<<endl;
 31 int t[MAXN][10];
 32 int sz,s[MAXN],c[100000];
 33 void add(char a[],char b[],char back[])//计算 a+b,结果存入 c,
 34 {
 35 
 36     int i,j,k;
 37     int x,y,z;
 38     int up;
 39     i=strlen(a)-1;
 40     j=strlen(b)-1;
 41     k=0;
 42     up=0;
 43     while(i>=0||j>=0)
 44     {
 45         if(i<0)x=0;
 46         else x=a[i]-'0';
 47         if(j<0)y=0;
 48         else y=b[j]-'0';
 49         z=x+y+up;
 50         c[k++]=z%10+'0';
 51         up=z/10;
 52         i--;
 53         j--;
 54     }
 55     if(up>0)c[k++]=up+'0';
 56     for(i=0;i<k;i++)back[i]=c[k-1-i];
 57     back[k]='\0';
 58 }
 59 void insert(char ch[],int idx)
 60 {
 61     int k,len=strlen(ch),now=0;
 62     len=min(len,41);
 63     Rep(p,len)
 64     {
 65         k=ch[p]-'0';
 66         if(t[now][k]==0) t[now][k]=++sz,s[t[now][k]]=idx;
 67         now=t[now][k];
 68 
 69     }
 70 }
 71 int ask(char ch[])
 72 {
 73     int len=strlen(ch),k,now=0;
 74     Rep(p,len)
 75     {
 76         k=ch[p]-'0';
 77         if(t[now][k]==0) return -1;
 78         now=t[now][k];
 79     }
 80     return s[now];
 81 }
 82 char now[100],pre[100],buf[100];
 83 void init()
 84 {
 85     NEG(s);
 86     now[0]='1';now[1]=0;
 87     pre[0]='1';pre[1]=0;
 88     insert(now,0);
 89     Fork(i,2,99999)
 90     {
 91         add(now,pre,buf);
 92         strcpy(pre,now);
 93         strcpy(now,buf);
 94         int len1=strlen(pre),len2=strlen(now);
 95         if(len2>60) pre[len1-1]=0,now[len2-1]=0;
 96         insert(now,i);
 97     }
 98 }
 99 int main()
100 {
101     int T;
102     scanf("%d",&T);
103     init();
104     For(kases,T)
105     {
106         scanf("%s",buf);
107         printf("Case #%d: %d\n",kases,ask(buf));
108     }
109     return 0;
110 }
View Code

 

poj1056

http://poj.org/problem?id=1056

和hdu1617完全一模一样

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<functional>
 6 #include<iostream>
 7 #include<cmath>
 8 #include<string>
 9 #include<cctype>
10 #include<stack>
11 #include<set>
12 #include<map>
13 #include<ctime>
14 using namespace std;
15 #define For(i,n) for(int i=1;i<=n;i++)
16 #define Fork(i,k,n) for(int i=k;i<=n;i++)
17 #define Rep(i,n) for(int i=0;i<n;i++)
18 #define ForD(i,n) for(int i=n;i;i--)
19 #define RepD(i,n) for(int i=n;i>=0;i--)
20 #define Forp(x) for(int p=pre[x];p;p=next[p])
21 #define Lson (x<<1)
22 #define Rson ((x<<1)+1)
23 #define MEM(a) memset(a,0,sizeof(a));
24 #define NEG(a) memset(a,-1,sizeof(a));
25 #define INF 0x3f3f3f3f
26 #define LLINF 0x3f3f3f3f3f3f3f3f
27 #define MAXN 20000
28 #define ll long long
29 int t[MAXN][11];
30 int sz,s[MAXN];
31 int insert(char ch[])
32 {
33     int flg=1;
34     int k,len=strlen(ch),now=0;
35     Rep(p,len)
36     {
37         k=ch[p]-'0';
38         if(t[now][k]==0) t[now][k]=++sz;
39         now=t[now][k];
40         if((s[now]==1&&p==len-1)||s[now]==2)
41         {
42             flg=0;
43         }
44         //printf("now=%d\n",now);
45         s[now]=1;
46     }
47     s[now]=2;
48     return flg;
49 }
50 char buf[10000];
51 int main()
52 {
53     int kases=1,flg=1;
54     while(gets(buf)){
55         if(strcmp(buf,"9")==0)
56         {
57             printf("Set %d is",kases);
58             if(!flg) printf(" not");
59             printf(" immediately decodable\n");
60             kases++;
61             sz=0;
62             MEM(s);
63             MEM(t);
64             flg=1;
65         }
66         flg&=insert(buf);
67     }
68 
69 }
View Code

 

poj2513 
http://poj.org/problem?id=2513
题意理解错误,要求的是所有的木棒连接,连接条件是连接处同色。
颜色显然要hash成编码,所以会有两种思路,本质相同,一种map,
一种是trie树进行编码,每次用的时候查询编码过没有。之后是解决所有
木棒连接回路,那么就是欧拉回路,连通性要用到并查集。
还犯了一个错误就是套模板的时候数字trie树是-'0'的字母trie树是-'a'的
 
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<functional>
 6 #include<iostream>
 7 #include<cmath>
 8 #include<string>
 9 #include<cctype>
10 #include<stack>
11 #include<set>
12 #include<map>
13 #include<ctime>
14 using namespace std;
15 #define For(i,n) for(int i=1;i<=n;i++)
16 #define Fork(i,k,n) for(int i=k;i<=n;i++)
17 #define Rep(i,n) for(int i=0;i<n;i++)
18 #define ForD(i,n) for(int i=n;i;i--)
19 #define RepD(i,n) for(int i=n;i>=0;i--)
20 #define Forp(x) for(int p=pre[x];p;p=next[p])
21 #define Lson (x<<1)
22 #define Rson ((x<<1)+1)
23 #define MEM(a) memset(a,0,sizeof(a));
24 #define NEG(a) memset(a,-1,sizeof(a));
25 #define INF 0x3f3f3f3f
26 #define LLINF 0x3f3f3f3f3f3f3f3f
27 #define MAXN 1000000
28 #define ll long long
29 int t[MAXN][26];
30 int f[MAXN];
31 int sz,s[MAXN],nume;
32 int insert(char ch[])
33 {
34     int k,len=strlen(ch),now=0;
35     Rep(p,len)
36     {
37         k=ch[p]-'a';
38         if(t[now][k]==0) t[now][k]=++sz;
39         now=t[now][k];
40     }
41     if(s[now]==0) s[now]=++nume;
42     return s[now];
43 }
44 int get(int u)
45 {
46     return f[u]==u?u:f[u]=get(f[u]);
47 }
48 int degree[MAXN];
49 char buf[2][10000];
50 int main()
51 {
52     For(i,MAXN)
53     {
54         f[i]=i;
55     }
56     memset(degree,0,sizeof(degree));
57     while(scanf("%s %s",buf[0],buf[1])!=2)//&&buf[0][0]!='0')
58     {
59         int idx1=insert(buf[0]),
60         idx2=insert(buf[1]);
61         degree[idx1]++;
62         degree[idx2]++;
63        // printf("idx1=%d idx2=%d\n",idx1,idx2);
64         int fa=get(idx1),fb=get(idx2);
65         if(fa!=fb)
66         {
67             f[fa]=fb;
68         }
69     }
70     int cnt1=0,cnt2=0;
71     for(int i=1;i<=nume;i++)
72     {
73         if(get(i)==i)cnt1++;
74         if(degree[i]%2==1)cnt2++;
75         if(cnt1>1)break;
76         if(cnt2>2)break;
77     }
78     if((cnt1==0||cnt1==1)&&(cnt2==0||cnt2==2))
79       printf("Possible\n");
80     else printf("Impossible\n");
81     return 0;
82 
83     return 0;
84 }
View Code

 

 

自动机

hdu2222

http://acm.hdu.edu.cn/showproblem.php?pid=2222

字符串集合S,给出一个模式串T,问S中字符串在T中出现多少个,可重叠,S是multiset

trie树的功能是判断有没有,出现在S中以及S中的成员关系,

相对的,自动机解决的是模式与模板之间的关系,

字符串集合的构造显然和trie树一样,模板的匹配用的就和kmp一样,

之后要注意的是在query时每匹配中一个字符串就要把val清空以防止重复统计

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <queue>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int maxn=500000+10;
 8 const int maxl=1000000+10;
 9 queue<int>que;
10 struct trie{
11     int a[maxn][26];
12     int fail[maxn];
13     int val[maxn];
14     int sz,ans;
15 
16     void init(){
17         sz=0;
18         memset(a,0,sizeof(a));
19         memset(val,0,sizeof(val));
20         ans=0;
21     }
22 
23     int idx(char c) { return c-'a'; }
24 
25     void insert(char s[]){
26         int i,n,now=0;
27         n=strlen(s);
28         for(i=0;i<n;i++){
29             int id=idx(s[i]);
30             if(a[now][id]==0) a[now][id]=++sz;
31             now=a[now][id];
32         }
33         val[now]++;
34     }
35 
36     void acmatch(){
37         fail[0]=0;
38         int i;
39         for(i=0;i<26;i++){
40             int u=a[0][i];
41             if(u){
42                 fail[u]=0;que.push(u);
43             }
44         }
45         while(!que.empty()){
46             int r=que.front();que.pop();
47             for(int c=0;c<26;c++){
48                 int u=a[r][c];
49                 if(!u) continue;
50                 que.push(u);            
51                 int v=fail[r];
52                 while(v && !a[v][c]) v=fail[v];
53                 fail[u]=a[v][c];              
54             }
55         }
56     }
57 
58     void query(char s[]){
59         int i,n,now=0;
60         n=strlen(s);
61         for(i=0;i<n;i++){
62             int id=idx(s[i]);
63             while(now && !a[now][id]){
64                 now=fail[now];
65             }
66             now=a[now][id];
67             int t=now;
68             while(t)
69             {
70                 ans+=val[t];
71                 val[t]=0;
72                 t=fail[t];
73             }
74         }
75     }
76 };
77 
78 trie ac;
79 char str[maxl],word[100];
80 
81 int main()
82 {
83     int i,j,n,T;
84     scanf("%d",&T);
85     while(T--){
86         ac.init();
87         scanf("%d",&n);
88         for(i=0;i<n;i++){
89             scanf("%s",word);
90             ac.insert(word);
91         }
92         ac.acmatch();
93         scanf("%s",str);
94         ac.query(str);
95         printf("%d\n",ac.ans);
96     }
97     return 0;
98 }
View Code

 

hdu2825

http://acm.hdu.edu.cn/showproblem.php?pid=2825

给定一个字符串集合S,给出一个模式串T的长度,问S中字符串在T中出现至少k次有多少种方案,S可以重叠

一开始想法是d[i][j][k]表示匹配到i长度,j状态,出现k次,但是要注意的是可能重复出现S字符串,又k比较小

所以应该k换成s状态压缩表示已经出现的字符串集合。ac自动机+dp中,dp用到的是dp的单词标记。

这题比较难代码是抄的,有机会重现自己写一遍。

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <algorithm>
  5 #include <queue>
  6 using namespace std;
  7 const int MOD=20090717;
  8 int n,m,k;
  9 int dp[30][110][1<<10];
 10 int num[5000];
 11 
 12 struct Trie
 13 {
 14     int next[110][26],fail[110],end[110];
 15     int root,L;
 16     int newnode()
 17     {
 18         for(int i = 0;i < 26;i++)
 19             next[L][i] = -1;
 20         end[L++] = 0;
 21         return L-1;
 22     }
 23     void init()
 24     {
 25         L = 0;
 26         root = newnode();
 27     }
 28     void insert(char buf[],int id)
 29     {
 30         int len = strlen(buf);
 31         int now = root;
 32         for(int i = 0;i < len;i++)
 33         {
 34             if(next[now][buf[i]-'a']==-1)
 35                 next[now][buf[i]-'a'] = newnode();
 36             now = next[now][buf[i]-'a'];
 37         }
 38         end[now] |= (1<<id);
 39     }
 40     void acmatch()
 41     {
 42         queue<int>Q;
 43         fail[root] = root;
 44         for(int i = 0;i < 26;i++)
 45             if(next[root][i] == -1)
 46                 next[root][i] = root;
 47             else
 48             {
 49                 fail[next[root][i]] = root;
 50                 Q.push(next[root][i]);
 51             }
 52         while(!Q.empty())
 53         {
 54             int now = Q.front();
 55             Q.pop();
 56             end[now] |= end[fail[now]];
 57             for(int i = 0;i < 26;i++)
 58                 if(next[now][i] == -1)
 59                     next[now][i] = next[fail[now]][i];
 60                 else
 61                 {
 62                     fail[next[now][i]] = next[fail[now]][i];
 63                     Q.push(next[now][i]);
 64                 }
 65         }
 66     }
 67     int solve()
 68     {
 69         //memset(dp,0,sizeof(dp));
 70         for(int i = 0;i <= n;i++)
 71             for(int j = 0;j < L;j++)
 72                 for(int p = 0;p < (1<<m);p++)
 73                     dp[i][j][p]=0;
 74         dp[0][0][0] = 1;
 75         for(int i = 0;i < n;i++)
 76             for(int j = 0;j < L;j++)
 77                 for(int p = 0;p< (1<<m);p++)
 78                     if(dp[i][j][p] > 0)
 79                     {
 80                         for(int x = 0;x < 26;x++)
 81                         {
 82                             int newi = i+1;
 83                             int newj = next[j][x];
 84                             int newp = (p|end[newj]);
 85                             dp[newi][newj][newp] += dp[i][j][p];
 86                             dp[newi][newj][newp]%=MOD;
 87                         }
 88                     }
 89         int ans = 0;
 90         for(int p = 0;p < (1<<m);p++)
 91         {
 92             if(num[p] < k)continue;
 93             for(int i = 0;i < L;i++)
 94             {
 95                 ans = (ans + dp[n][i][p])%MOD;
 96             }
 97         }
 98         return ans;
 99     }
100 };
101 char buf[20];
102 Trie ac;
103 int main()
104 {
105     for(int i=0;i<(1<<10);i++)
106     {
107         num[i] = 0;
108         for(int j = 0;j < 10;j++)
109             if(i & (1<<j))
110                 num[i]++;
111     }
112     while(scanf("%d%d%d",&n,&m,&k)==3)
113     {
114         if(n== 0 && m==0 &&k==0)break;
115         ac.init();
116         for(int i = 0;i < m;i++)
117         {
118             scanf("%s",buf);
119             ac.insert(buf,i);
120         }
121         ac.acmatch();
122         printf("%d\n",ac.solve());
123     }
124     return 0;
125 }
View Code

 

 

后缀数组

posted @ 2016-07-25 17:16  aidgn  阅读(154)  评论(0编辑  收藏  举报