Tire树,hdu2846,hdu4825

hdu4825                      hdu2846

放一张图来解释tire树的构成(u1s1个人感觉像是hash表)

查询有多少前缀相同字符串的模板

 1 int cnt = 1;
 2 int g[26 * maxn][26], vis[26 * maxn], v[26 * maxn];
 3 il void add(char *w,int id){
 4     int p = 0, l = strlen(w);
 5     for (int i = 0; i < l; i++){
 6         int c = w[i] - 'a';
 7         if (!g[p][c]){
 8             g[p][c] = cnt++;
 9         }
10         vis[g[p][c]]++;
11         p = g[p][c];
12     }
13 }
14 il int query(char *w){
15     int p = 0, l = strlen(w);
16     for (int i = 0; i < l; i++){
17         int c = w[i] - 'a';
18         if (!g[p][c]){
19             return 0;
20         }
21         p = g[p][c];
22     }
23     return vis[p];
24 }

 

 

hdu4825

题意:

给长度为n的数组Ki(1<=i<=n),再输入m个S,在集合当中找出一个正整数 Ki ,使得 Ki 与 S 的异或结果最大

样例输入                                 输出:

2                                             Case #1:
3 2                                          4
3 4 5                                       3
1                                             Case #2:
5                                             4
4 1
4 6 5 6
3
 

思路:

字典树把每个数用二进制从高位到低位保存,因为高位影响较大。

寻找与S每个位都不一样的数字,但是如果哪一位没有不一样的,那只能找一样的了

 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define pii pair<int,int>
#define mak(n,m) make_pair(n,m)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 998244353
const int maxn=1e5+10;
ll g[maxn*32][2],cnt, m, n, a;
ll vis[maxn*32];
il void add(ll n){
    ll p=0;
    for (it i = 32; i >= 0; i--){
        int c = (n >> i) & 1;
        if (!g[p][c]){
            g[p][c]=cnt++;
        }
        p = g[p][c];
    }
    vis[p] = n;
}
il void query(ll n){
    ll p = 0;
    for (it i = 32; i >= 0; i--){
        int c = 1 - (n >> i) & 1;
        if (!g[p][c]){
            c = 1 - c;
        }
        p = g[p][c];
    }
    printf("%lld\n", vis[p]);
}
int main(){
    int c=1, t;
    scanf("%lld",&t);
    while (t--){
        cnt= 1;
        mem(vis, 0);mem(g, 0);
        scanf("%lld%lld",&n,&m);
        for (it i = 0; i < n; i++){
            scanf("%lld",&a);
            add(a);
        }
        printf("Case #%d:\n",c++);
        for (it i = 0; i < m; i++){
            scanf("%lld",&a);
            query(a);
        }
    }
    return 0;
}

 

 

 

hdu2846

题意:

给n个字符串,再给m个字符串S,问S在n个字符串中是其子串

样例输入                                   输出

2                                                2

adad

dadd

1

ad

 

思路:

tire树,边存字符串边记录cnt出现几次。因为他要子串,所以长度较小所以可以直接暴力o(n^2),把每个子串存进去

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define pii pair<int,int>
#define mak(n,m) make_pair(n,m)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 998244353
const int maxn=1e5+10;
char s[30];
int k = 1, n, m;
int g[26 * maxn][26], vis[26 * maxn], v[26 * maxn];
il void add(char *w,int id){
    int p = 0, l = strlen(w);
    for (it i = 0; i < l; i++){
        int c = w[i] - 'a';
        if (!g[p][c]){
            g[p][c] = k++;
            vis[g[p][c]]++;
            v[g[p][c]] = id;
        }
        p = g[p][c];
        if (v[p] != id){
            vis[p]++;
            v[p] = id;
        }
    }
}
il int query(char *w){
    int p = 0, l = strlen(w);
    for (it i = 0; i < l; i++){
        int c = w[i] - 'a';
        if (!g[p][c]){
            return 0;
        }
        p = g[p][c];
    }
    return vis[p];
}
int main(){
    scanf("%d",&n);
    for (it i = 0; i < n; i++){
        scanf("%s",&s);
        int l = strlen(s);
        for (it j = 0; j < l; j++){
            add(s + j, i);
        }
    }
    scanf("%d",&m);
    for (it i = 0; i < m; i++){
        scanf("%s",&s);
        printf("%d\n",query(s));
    }
    return 0;
}

 

posted @ 2020-03-11 15:19  ouluy  阅读(165)  评论(0编辑  收藏  举报