HDU Bazinga(KMP+并查集)

Bazinga

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 5088 Accepted Submission(s): 1606

Problem Description
Ladies and gentlemen, please sit up straight.
Don’t tilt your head. I’m serious.

For n given strings S1,S2,⋯,Sn, labelled from 1 to n, you should find the largest i (1≤i≤n) such that there exists an integer j (1≤j< i) and Sj is not a substring of Si.

A substring of a string Si is another string that occurs in Si. For example, ruiz" is a substring ofruizhang”, and rzhang" is not a substring ofruizhang”.

Input
The first line contains an integer t (1≤t≤50) which is the number of test cases.
For each test case, the first line is the positive integer n (1≤n≤500) and in the following n lines list are the strings S1,S2,⋯,Sn.
All strings are given in lower-case letters and strings are no longer than 2000 letters.

Output
For each test case, output the largest label you get. If it does not exist, output −1.

Sample Input
4
5
ab
abc
zabc
abcd
zabcd
4
you
lovinyou
aboutlovinyou
allaboutlovinyou
5
de
def
abcd
abcde
abcdef
3
a
ba
ccc

Sample Output
Case #1: 4
Case #2: -1
Case #3: 4

题意:给出n个串,当1~i-1之间任意一串不能与i匹配时,i满足条件,输出最大的i,如果都没有,输出-1

强行暴力,T了好几发,于是我开始考虑重复问题,一个串如果和另一个串能匹配,那么,这俩串只需要判断一次后者就行了,如果后者能匹配,那么前者一定能匹配。
那么如何判断这种串与串关系呢?多亏队友提醒,并查集啊!
我可以每次将这些互相包含的串加入一个集合中,这样每次匹配时,直接判断要匹配的串在不在一个集合里就行了,如果在的话,就不用匹配,如果不在,继续匹配;
还有,每次匹配的时候都要倒着来;因为只有倒着来,这个串包含前面的串,才能包含上面集合的判断条件,如果正着来,每次先和小串匹配,然后改变大串的集合,这显然是不满足条件的
然后,因为不知道,所给的串是不是长度严格递增的,加了一行判断,如果后面长度小于前面直接刷新(事实上后台数据是严格递增的),本来匹配是用find写的,百度说复杂度n*m,吓得我手敲了一遍KMP,结果find比KMP快,看来重复串比较多。。。
#include<bits/stdc++.h>
#define wtf printf("wtf\n");
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1e6+20;
string s[505];
int nxt[2005];
int f[505],n;
void get_nxt(string t)
{
    int i=0,j=-1,len=t.size();
    nxt[0]=-1;
    while(i<len)
    {
        if(j==-1||t[i]==t[j])
        {
            nxt[++i]=++j;
        }
        else
            j=nxt[j];
    }
}
bool kmp(string S,string T)
{
    get_nxt(T);
    int i=0,j=0,la=S.size(),lb=T.size();
    while(i<la&&j<lb)
    {
        if(j==-1||S[i]==T[j])
        {
            i++,j++;
        }
        else
            j=nxt[j];
    }
    if(j==lb)return true;
    return false;
}
int getf(int x)
{
    if(x==f[x])return x;
    else
        f[x]=getf(f[x]);
    return f[x];
}
void mix(int x,int y)
{
    int tx=getf(x);
    int ty=getf(y);
    if(tx!=ty)
    {
        f[tx]=ty;
    }
}
void init()
{
    for(int i=1; i<=n; i++)
        f[i]=i;
}
int main()
{
    std::ios::sync_with_stdio(false);
    int t,q=0;
    cin>>t;
    while(t--)
    {
        cin>>n;
        init();
        for(int i=1; i<=n; i++)
        {
            cin>>s[i];
        }
        int now=-1,top=1;
        for(int i=1; i<=n; i++)
        {
            for(int j=i-1; j>=1; j--)
            {
                if(getf(i)==getf(j))//判断是否同一集合
                {
                    continue;
                }
                else
                {
                    if(s[i].size()<s[j].size()||!kmp(s[i],s[j]))//长度小于前面或者出现不匹配
                    {
                         now=i;
                        break;
                    }
                    else
                        mix(i,j);//匹配成功,则加入同一集合
                }
            }
        }
        printf("Case #%d: %d\n",++q,now);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值