蓝书2.3 Trie字典树
T1 IMMEDIATE DECODABILITY poj 1056
题目大意:
一些数字串 求是否存在一个串是另一个串的前缀
思路:
对于所有串经过的点权+1 如果一个点的end被访问过或经过一个被标记为end的点 就存在
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 15100 13 using namespace std; 14 inline int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 18 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 int n,tr[100][2],T,ans,vis[MAXN],sz,end[MAXN]; 22 char ch[15]; 23 void ins(char *c,int len) 24 { 25 int pos=0; 26 for(int i=0;i<len;i++) 27 { 28 if(!tr[pos][c[i]-'0']) tr[pos][c[i]-'0']=++sz; 29 pos=tr[pos][c[i]-'0'],vis[pos]++; 30 if(end[pos]) ans=1; 31 } 32 if(vis[pos]>1) ans=1;end[pos]=1; 33 } 34 int main() 35 { 36 while(scanf("%s",ch)!=EOF) 37 { 38 ans=sz=0;memset(vis,0,sizeof(vis)); 39 memset(tr,0,sizeof(tr));memset(end,0,sizeof(end)); 40 while(ch[0]!='9'){ins(ch,strlen(ch));scanf("%s",ch);} 41 if(!ans) printf("Set %d is immediately decodable\n",++T); 42 else printf("Set %d is not immediately decodable\n",++T); 43 } 44 }
T2 L语言 bzoj 1212
题目大意:
给字典 求一个字符串能被字典解释的最长前缀
思路:
因为字典内的单词都很短
可以对每一个模式串的位置向后匹配递推
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 1000100 13 using namespace std; 14 inline int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 18 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 int n,m,tr[220][30],sz,end[MAXN],f[MAXN]; 22 char ch[15],s[MAXN]; 23 void ins(char *c,int len) 24 { 25 int pos=0; 26 for(int i=0;i<len;i++) 27 { 28 if(!tr[pos][c[i]-'a']) tr[pos][c[i]-'a']=++sz; 29 pos=tr[pos][c[i]-'a']; 30 } 31 end[pos]=1; 32 } 33 int query(char *c,int len) 34 { 35 int pos=0,res=0,k; 36 if(tr[pos][c[0]-'a']) f[0]=1; 37 else return 0; 38 for(int i=0;i<len;i++) 39 { 40 if(!f[i]) continue; 41 pos=tr[pos][c[i]-'a'],k=0; 42 while(pos) 43 { 44 if(end[pos]) f[i+k+1]=1,res=max(res,min(i+k+1,len)); 45 pos=tr[pos][c[i+k+1]-'a'],k++; 46 } 47 } 48 return res; 49 } 50 int main() 51 { 52 n=read(),m=read(); 53 for(int i=1;i<=n;i++) {scanf("%s",ch);ins(ch,strlen(ch));} 54 while(m--) 55 { 56 scanf("%s",s);memset(f,0,sizeof(f)); 57 printf("%d\n",query(s,strlen(s))); 58 } 59 }
T3 秘密信息 bzoj 1590
题目大意:
n个信息 m个密码 对每个密码求有多少信息与它匹配 也就是说,有多少信息和这条密码有着相同的前缀
思路:
加到字典序里记一下经过的end标记和这个密码的end位置有多少个信息经过
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 using namespace std; 14 inline int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 18 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 int n,m,tr[MAXN][2],sz,end[MAXN],s[MAXN]; 22 void ins(int len) 23 { 24 int pos=0; 25 for(int i=0,k;i<len;i++) 26 { 27 k=read(); 28 if(!tr[pos][k]) tr[pos][k]=++sz; 29 pos=tr[pos][k],s[pos]++; 30 } 31 end[pos]++; 32 } 33 int query(int len) 34 { 35 int pos=0,res=0,f=0; 36 for(int i=0,k;i<len;i++) 37 { 38 k=read(); 39 if(f) continue;pos=tr[pos][k]; 40 if(!pos) f=1; 41 if(i!=len-1) res+=end[pos]; 42 } 43 if(!f) res+=s[pos]; 44 return res; 45 } 46 int main() 47 { 48 n=read(),m=read();int k; 49 for(int i=1;i<=n;i++) {k=read();ins(k);} 50 while(m--) {k=read();printf("%d\n",query(k));} 51 }
T4 背单词 bzoj 4567
题目大意:
放n个单词,放每个单词之前如果没有把这个单词的后缀都先放上去则代价为n*n)
每个单词的代价等于这个单词的位置减去上一个出现的这个单词的后缀的位置(若没有后缀则代价为它的位置)
求最少的代价
思路:
首先肯定要把所有单词的后缀都加入否则代价太大
然后倒着把单词加入建trie树 对于所有end节点向上最近的end连边
可以得到一个树 每个树按照size从小到大遍历
答案就是所有节点的序号-父亲的序号
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 using namespace std; 14 inline int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 18 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 int n,m,tr[MAXN][30],tot,end[MAXN],st[MAXN],top; 22 ll ans; 23 char ch[MAXN],s[MAXN]; 24 int fst[MAXN],nxt[MAXN],to[MAXN],cnt,fa[MAXN],sz[MAXN]; 25 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;} 26 void ins(char *c,int len) 27 { 28 int pos=0,tmp=0; 29 for(int i=len-1;i>=0;i--) 30 { 31 if(!tr[pos][c[i]-'a']) tr[pos][c[i]-'a']=++tot; 32 pos=tr[pos][c[i]-'a']; 33 } 34 end[pos]=1; 35 } 36 void dfs(int x,int anc) 37 { 38 if(end[x]) {add(x,anc);add(anc,x);fa[x]=anc,anc=x;} 39 for(int i=0;i<26;i++) 40 if(tr[x][i]) dfs(tr[x][i],anc); 41 } 42 void build(int x) 43 { 44 sz[x]=1; 45 for(int i=fst[x];i;i=nxt[i]) 46 if(to[i]!=fa[x]) {build(to[i]);sz[x]+=sz[to[i]];} 47 } 48 bool cmp(int x,int y) {return sz[x]<sz[y];} 49 void dfs(int x) 50 { 51 int l=top+1,r;ll s=1; 52 for(int i=fst[x];i;i=nxt[i]) if(to[i]!=fa[x])st[++top]=to[i]; 53 sort(st+l,st+top+1,cmp);r=top; 54 for(int i=l;i<=r;i++) {ans+=s,s+=sz[st[i]];dfs(st[i]);} 55 } 56 int main() 57 { 58 n=read(); 59 for(int i=1;i<=n;i++) {scanf("%s",ch);ins(ch,strlen(ch));} 60 dfs(0,0);build(0);dfs(0);printf("%lld\n",ans); 61 }
T5 The xor-longest Path bzoj 1954
题解链接 唯一的区别是poj 从0开始