jzoi4964

思路是先对每个(k-1)长度的子字符串之间建边,然后拓扑,若有环则最终仍有indg[i]为 0的

这题用字符串哈希的话会超时

以下是30分做法

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define mo 9223372036854775807
#define ll unsigned long long
using namespace std;
const int maxn=1e5+2;
const int hx=2000000;
int n,k,cnt,to[maxn],ans,head[maxn],nex[maxn],indg[hx],dis[hx];
char s[maxn];
bool vis[hx];
queue<int>q;
ll hsh[hx];
ll ksm(int x,int y){
    ll t=1;
    while(y){
        if(y&1)t=t*x%mo;
        x=x*x%mo;
        y>>=1;
    }
    return t;
}
ll hash(ll x){
    ll pos=x%hx;
    while(hsh[pos]&&hsh[pos]!=x)pos=(pos+1)%hx;
    hsh[pos]=x;
    return pos;
}
void addedge(int u,int v){
    indg[v]++;vis[u]=vis[v]=1;
    to[++cnt]=v;nex[cnt]=head[u];head[u]=cnt;
}
void topo(){
    while(!q.empty()){
        int u=q.front();q.pop();
        ans=max(ans,dis[u]);
        for(int i=head[u];i;i=nex[i]){
            int v=to[i];
            dis[v]=max(dis[v],dis[u]+1);
            if(!(--indg[v]))q.push(v);
        }
    }
}
int main(){
    while(~scanf("%d%d",&n,&k)){
        ll kk=ksm(26,k-1);
        cnt=1;
        memset(head,0,sizeof(head));
        memset(indg,0,sizeof(indg));
        memset(vis,0,sizeof(vis));
        while(n--){
            scanf("%s",s+1);
            int len=strlen(s+1);
            if(len<k)continue;
            for(int i=1;i<=len;i++)s[i]=s[i]-'a'+1;
            ll t=0;
            for(int i=1;i<k;i++)t=t*26+s[i];
            for(int i=k;i<=len;i++){
                ll u=hash(t);
                t=t*26+s[i]-kk*s[i-k+1];
                ll v=hash(t);
                addedge(u,v);
            }
        }
        ans=k-1;
        for(int i=0;i<hx;i++)
           if(vis[i]&&!indg[i]){q.push(i);dis[i]=k-1;}
        topo();
        bool flag=0;
        for(int i=0;i<hx;i++)if(indg[i]){
            flag=1;break;
        }
        if(flag)printf("INF\n");else printf("%d\n",ans);
    }
}

满分用map

#include<cstdio>
#include<string>
#include<map>
#include<queue>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=1e5,hx=6e6;
string s[maxn];
int n,k,ans,cnt,tot,nex[hx],head[hx],to[hx],dis[hx],vis[hx],indg[hx];
map<string,int>m;
int hash(string ss){
    int &pos=m[ss];
    if(!pos)pos=++tot;
    return pos;
}
void addedge(int u,int v){
    indg[v]++;to[++cnt]=v;nex[cnt]=head[u];head[u]=cnt;
}
queue<int>q;
void topo(){
    while(!q.empty()){
        int u=q.front();q.pop();
        ans=max(ans,dis[u]);
        for(int i=head[u];i;i=nex[i]){
            dis[to[i]]=max(dis[to[i]],dis[u]+1);
            if(--indg[to[i]]==0)
            q.push(to[i]);
        }
    }
}
int main(){
    while(~scanf("%d%d",&n,&k)){
        cnt=tot=ans=0;
        memset(head,0,sizeof(head));
        memset(vis,0,sizeof(vis));
        memset(dis,0,sizeof(dis));
        memset(indg,0,sizeof(indg));
        m.clear();
        for(int i=1;i<=n;i++){
            cin>>s[i];
            for(int j=0;j+k-1<s[i].size();j++){
                addedge(hash(s[i].substr(j,k-1)),hash(s[i].substr(j+1,k-1)));
            }
        }
        for(int i=1;i<=tot;i++)
        if(!indg[i])
        q.push(i);
        topo();
        bool flag=0;
        for(int i=1;i<=tot;i++)if(indg[i]>0){flag=1;break;}
        if(flag)printf("INF\n");else printf("%d\n",ans+k-1);
    }
}

 

posted @ 2018-05-01 21:00  lnyzo  阅读(284)  评论(0编辑  收藏  举报