【Hash+拓扑】2017.10.20杂题[Rhyme]题解

5 篇文章 0 订阅
2 篇文章 0 订阅

题目概述

给出 n 个模板串,现在要求一个最长的串,使得该串中所有长度为 K 的子串都是一个模板的子串。如果可以无限长输出 INF

解题报告

其实不难吧……但是太弱了就没想出来。

对于每个模板,相邻两个长度为 K1 (不是 K ,因为两个 K1 子串组合成 K )的子串建边,然后刷拓扑,如果有环就是 INF ,否则是最长链 +K1

示例程序

自然溢出+map……

#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
typedef long long LL;typedef unsigned long long ULL;
const int maxl=1000000,Base=23333;

int n,K,tot;ULL Ha[maxl+5],pw[maxl+5];char s[maxl+5];
int E,lnk[maxl+5],son[maxl+5],nxt[maxl+5];
int f[maxl+5],que[maxl+5],dis[maxl+5];
map<ULL,int> ID;

#define Eoln(x) ((x)==10||(x)==13||(x)==EOF)
inline char readc()
{
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF;return *l++;
}
inline int readi(int &x)
{
    int tot=0,f=1;char ch=readc(),lst='+';
    while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
    if (lst=='-') f=-f;
    while ('0'<=ch&&ch<='9') tot=(tot<<1)+(tot<<3)+ch-48,ch=readc();
    return x=tot*f,Eoln(ch);
}
inline int reads(char *s)
{
    int len=0;char ch=readc();while ('z'<ch||ch<'a') ch=readc();
    s[++len]=ch;while ('a'<=s[len]&&s[len]<='z') s[++len]=readc();
    s[len--]=0;return len;
}
inline void Add(int x,int y) {son[++E]=y;nxt[E]=lnk[x];lnk[x]=E;}
#define Hash(L,R) (Ha[L]-Ha[(R)+1]*pw[(R)-(L)+1])
int main()
{
    freopen("B.in","r",stdin);
    freopen("B.out","w",stdout);
    pw[0]=1;for (int i=1;i<=maxl;i++) pw[i]=pw[i-1]*Base;
    while (~readi(n))
    {
        readi(K);K--;E=0;memset(lnk,0,sizeof(lnk));memset(f,0,sizeof(f));tot=0;ID.clear();
        for (int i=1;i<=n;i++)
        {
            int len=reads(s);if (len<=K) continue;Ha[len+1]=0;
            for (int j=len;j>=1;j--) Ha[j]=Ha[j+1]*Base+s[j];
            for (int j=K+1;j<=len;j++)
            {
                ULL lst=Hash(j-K,j-1),now=Hash(j-K+1,j);
                if (!ID.count(lst)) ID[lst]=++tot;if (!ID.count(now)) ID[now]=++tot;
                Add(ID[lst],ID[now]);f[ID[now]]++;
            }
        }
        int Head=0,Tail=0;for (int i=1;i<=tot;i++) if (!f[i]) que[++Tail]=i,dis[Tail]=0;
        while (Head!=Tail)
            for (int j=lnk[que[++Head]];j;j=nxt[j])
                if (!(--f[son[j]])) que[++Tail]=son[j],dis[Tail]=dis[Head]+1;
        if (Tail!=tot) printf("INF\n"); else printf("%d\n",K+dis[Tail]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值