HDU 5507 GT and strings 字符串相关暴力

GT and strings

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 277    Accepted Submission(s): 52


Problem Description
You are given  N  strings.Their total length is  L .

There are  Q  questions.

For each question please work out two tasks:

①whether  Sx  is a subsequence of  Sy .

②whether  Sx  is a substring of  Sy .

If the statement is true print  1 ,otherwise print  0
 

Input
In the first line there is the testcase  T .

For each teatcase:

In the first line there are two numbers  N  and  Q .

In the next  N  lines there are  N  strings  i -th line is a string standing for  Si .

**Note that  Si  consists of only lower alphabets.**

In the last  Q  lines there are two numbers (x,y) .

T5 N,L,Q100000 。Every string's length is at least  1

There are  60%  testcases that  L100 Q1000

You'd better print the enter in the last line when you hack others.

You'd better not print space in the last of each line when you hack others.
 

Output
For each testcase,print only one lines.

It's a string contains only  0  and  1  and its length is  Q2 .

i21 -th character is the answer of the  i -th question of ①,

and  i2 -th character is the answer of the  i -th question of ②。
 

Sample Input
  
  
1 6 6 orz stilwell skydec se dec orz 1 2 1 3 1 6 4 1 4 2 6 1
 

Sample Output
  
  
000011001011
 

Source
 
------------------------------------------------------------------------------------------------------------------------------------------------------------

题意:给n个字符串和q个询问,询问会给出两个数字x,y,问:1.x串是否是y串的子序列,2.x串是否是y串的子串。对于每个询问,输出两个字符,第一个为‘1’代表第一个询问正确,为‘0’代表第一个询问错误,第二个字符同理。

思路:必须说明这题数据有问题,题意就没有说清数据的范围,因此时间复杂度的估计没什么意义,并且自己也看了别人的代码才知道的数组开多大……总之做法就是比较暴力的做法,
对于第一种询问:先预处理,dp[i][j]代表字符串中第i个字符的后面字符中(包括它自己)'a'+j这个字符的位置,处理每个询问,用x字符串来走y字符串的dp数组,走完后的最后位置还在y里面的话就是‘1’,反之就是‘0’
对于第二种询问:子串问题很容易想到ac自动机,每个串insert的时候,给每个是串的结尾的节点一个编号,并每个串对应的编号记为jiedian[i]代表第i个串结尾在自动机的位置的节点编号(原谅我的尴尬英语……写的时候没注意,写好也不想因为这种问题去改了),拿所有y串走一遍ac自动机,因为问的是x是否为y的子串,则y串走ac自动机的时候一定会走到x串对应的结尾节点的,用map< pair< int , int >  bool >标记为map[make_pair(走到的节点编号,y串的节点编号)]=true(用set < pair< int , int >  bool >也完全没问题)。最后对于每个询问,看make_pair(x串的节点编号,y串的节点编号)的标记,即可知道询问答案。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
#define MS(x,y) memset(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
typedef pair<int,int> P;
const int MAXN=1e5+5;
const int INF=0x3f3f3f3f;

char str[MAXN];
int pos[MAXN],ans[MAXN][2],query[MAXN][2];
int dp[MAXN][26];
bool isqu[MAXN];
int T,n,m;

void solve1(){
    for(int i=0;i<26;++i) dp[pos[n]][i]=INF;
    for(int i=pos[n]-1;i>=0;--i){
        for(int j=0;j<26;++j) dp[i][j]=dp[i+1][j];
        dp[i][str[i]-'a']=i;
    }
    for(int i=0;i<m;++i){
        int u=query[i][0],v=query[i][1];
        if(pos[u]-pos[u-1]>pos[v]-pos[v-1]){
            ans[i][0]=0;
            continue;
        }
        int point=pos[v-1];
        bool flag=false;
        for(int j=pos[u-1];j<pos[u];++j){
            point=dp[point][str[j]-'a'];
            if(point>=pos[v]){
                flag=true;
                break;
            }
            ++point;
        }
        if(flag) ans[i][0]=0;
        else ans[i][0]=1;
    }
}
//int DP(int x,int y){
//    int gui=pos[x-1],i=pos[y-1];
//    if(pos[x]-pos[x-1]>pos[y]-pos[y-1]) return 0;
//    while(gui<pos[x]){
//        int tt=str[gui]-'a';
//        if(dp[i][tt]>=pos[y]) return 0;
//        gui++;
//        i=dp[i][tt];++i;
//    }
//    return 1;
//}
//void solve1(){
//    for(int i=0;i<26;++i) dp[pos[n]][i]=INF;
//    for(int j=pos[n]-1;j>=pos[0];--j){
//        for(int k=0;k<26;++k)
//            if(str[j]-'a'==k) dp[j][k]=j;
//            else dp[j][k]=dp[j+1][k];
//    }
//    for(int i=0;i<m;++i)
//        ans[i][0]=DP(query[i][0],query[i][1]);
//}

struct Tire{
    int nxt[MAXN][26],fail[MAXN],cnt[MAXN],jiedian[MAXN];
    int L,id;
    map<P,bool> mp;
    
//    int node(){
//        for(int i=0;i<26;++i) nxt[L][i]=-1;
//        cnt[L]=0;
//        return L++;
//    }
    void init(){
        mp.clear();
        id=L=0;
        MS(fail,0);
        MS(nxt,0);
        MS(cnt,0);
    }
    void insert(int x){
        int now=0;
        for(int i=pos[x-1];i<pos[x];++i){
            if(nxt[now][str[i]-'a']==0)
                nxt[now][str[i]-'a']=++L;
            now=nxt[now][str[i]-'a'];
        }
        if(!cnt[now]) cnt[now]=++id;
        jiedian[x]=cnt[now];
    }
    void build(){
        queue<int> Q;
        for(int i=0;i<26;++i){
            if(nxt[0][i]) Q.push(nxt[0][i]);
        }
        while(!Q.empty()){
            int t1=Q.front();Q.pop();
            for(int i=0;i<26;++i){
                int t2=nxt[t1][i];
                if(t2){
                    Q.push(t2);
                    int t3=fail[t1];
                    while(t3&&!nxt[t3][i]) t3=fail[t3];
                    fail[t2]=nxt[t3][i];
                }
            }
        }
    }
    
    void find(int y){
        int now=0;
        for(int i=pos[y-1];i<pos[y];++i){
            now=nxt[now][str[i]-'a'];
            for(int p=now;p;p=fail[p]){
                if(cnt[p]){
                    mp[MP(cnt[p],jiedian[y])]=true;
                }
                else{
                    if(fail[p]&&!cnt[fail[p]])
                        fail[p]=fail[fail[p]];
                }
            }
        }
    }
    void solve(){
        init();
        for(int i=1;i<=n;++i){
            insert(i);
        }
        build();
        for(int i=1;i<=n;++i)
            if(isqu[i]) find(i);
        for(int i=0;i<m;++i)
            ans[i][1]=mp[MP(jiedian[query[i][0]],jiedian[query[i][1]])];
    }
}ac;

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i){
            scanf("%s",str+pos[i-1]);
            pos[i]=strlen(str);
        }
        MS(isqu,false);
        for(int i=0;i<m;++i){
            scanf("%d%d",&query[i][0],&query[i][1]);
            isqu[query[i][1]]=true;
        }
        solve1();
        ac.solve();
        for(int i=0;i<m;++i) printf("%d%d",ans[i][0],ans[i][1]);
        putchar(10);
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值