【jzoj4964】【Rhyme】【字符串哈希】【拓扑排序】

23 篇文章 1 订阅
22 篇文章 0 订阅

题目大意

由于多次交换邮票没有满足所有人的需求,小Z被赶出了集邮部。无处可去的小Z决定加入音乐部,为了让音乐部的人注意到自己的才华,小Z想写一首曲子。为了让自己的曲子更好听,小Z找到了一些好听曲子作为模板。曲谱可以表示成只包含小写字母的字符串,小Z希望自己最终的曲谱中任意一个长度为K的子串都是一个模板的子串。现在小Z想知道自己的曲谱最长可以是多长,如果可以无限长的话请输出INF。

解题思路

将k-1的串哈希,枚举一个串去掉头枚举一个尾看是否在哈希内,是就连一条有向边。跑拓扑排序有环即inf,否则跑最长路。

code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define ULL unsigned long long
#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a>b)?a:b)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxl=1e5,mo=1e6+7;LL moo=1e9+7
int n,m,K,gra,to[maxl*26+10],next[maxl*26+10],begin[mo+10],dis[mo+10],
qu[mo+10],inq[mo+10],pre[mo+10],len,b[maxl+10];
char s[maxl+10];
ULL a[maxl+10],h[mo+10];
void insert(int u,int v){
    to[++gra]=v+1;pre[v+1]++;
    next[gra]=begin[u+1];
    begin[u+1]=gra;
}
int hash(ULL x){
    int y=x%mo;
    while(h[y]&&(h[y]!=x))y=y%mo+1;
    return y;
}
int main(){
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);int ha,cnt=0;
    while(scanf("%d%d\n",&n,&K)!=EOF){
        gra=0;fo(i,1,mo)begin[i]=pre[i]=h[i]=0;if(K==2)K++;
        ULL bit=1;fo(i,1,K-2)bit=bit*26;cnt=0;
        int ans=0;
        fo(cas,0,n-1){
            scanf("%s\n",&s[1]);len=strlen(&s[1]);
            if((len<K)&&(!((len==2))))continue;
            a[++cnt]=0;
            fo(i,1,K-1)a[cnt]=a[cnt]*26+s[i]-'a';ha=hash(a[cnt]),h[ha]=a[cnt],b[cnt]=s[1]-'a';
            fo(i,K,len)ha=hash(a[cnt+1]=(a[cnt]-(s[i-K+1]-'a')*bit)*26+s[i]-'a'),h[ha]=a[++cnt],b[cnt]=s[i-K+2]-'a';
            if(K<=len)cnt--;
        }
        fo(i,1,cnt)fo(j,0,25){
            ha=hash((a[i]-b[i]*bit)*26+j);
            if(h[ha])insert(hash(a[i]),ha);
        }
        int he=0,ti=0;
        fo(i,1,mo){
            dis[i]=K-1;
            if(!pre[i])inq[qu[++ti]=i]=1;
        }
        while(he!=ti){
            int now=qu[++he];
            for(int i=begin[now];i;i=next[i]){
                dis[to[i]]=max(dis[to[i]],dis[now]+1);
                if(!(--pre[to[i]]))inq[qu[++ti]=to[i]]=1;
            }
        }
        fo(i,1,mo)ans=max(ans,dis[i]);
        if((ti!=mo)||(K==1))printf("INF\n");
        else printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值