Codeforces 696D. Legen...

AC自动机上的倍增弗洛伊德

调了好长时间才发现size开小了。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
using namespace std;
#define ll long long
char c;
bool flag;
inline void read(ll &a)
{a=0;do c=getchar();while((c<'0'||c>'9')&&c!='-');c=c=='-'?flag=true,getchar():c;while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();a=flag?flag=false,-a:a;}
inline ll Max(ll &a,ll b){return a>b?a:a=b;}
inline ll Min(ll &a,ll b){return a<b?a:a=b;}
inline ll min(ll a,ll b){return a<b?a:b;}
inline ll max(ll a,ll b){return a>b?a:b;}
inline ll abs(ll a){return a>0?a:-a;}



struct A
{
    int x,y;
    ll a[201][201];
    A(){}
    A(int x,int y):x(x),y(y){memset(a,-1,sizeof(a));}
    //ll *operator [](ll x){return a[x];}
    void In(){for(int i=0;i<=200;i++)a[i][i]=0;}
    A operator *(A b)
    {
        A c(x,b.y);
        for(int k=0;k<=y;k++)
            for(int i=0;i<=x;i++)
                if(~a[i][k])for(int j=0;j<=b.y;j++)
                if(~b.a[k][j])
                    {
                        if(i==13&&j==11&&k==12)
                            i++,i--;
                        Max(c.a[i][j],a[i][k]+b.a[k][j]);
                    }
        return c;
    }
};


A Pow(A x,ll t)
{
    A res(x.x,x.y);
    res.In();
    for(t;t;t>>=1,x=x*x)
        if(t&1)
            res=res*x;
    return res;
}


struct Node
{
    int no;
    Node *ch[27],*last[27],*f;
    int Val;
    Node(){memset(ch,0,sizeof(ch));Val=no=0;}
    Node(int no):no(no){memset(ch,0,sizeof(ch));Val=0;}
}*Root=new Node;

char S[301];

int size;
ll Data[301];
inline void Add(int i)
{   
    scanf("%s",S+1);
    int n=strlen(S+1);
    Node *tp=Root;
    for(int i=1;i<=n;tp=tp->ch[S[i++]-'a'])
        if(!tp->ch[S[i]-'a']){tp->ch[S[i]-'a']=new Node(++size);}
    tp->Val+=Data[i];
}
queue<Node*>Q;
inline void BFS()
{
    for(int i=0;i<=26;i++)
    if(Root->ch[i])
        Q.push(Root->ch[i]),Root->ch[i]->f=Root,Root->last[i]=Root->ch[i];
    else Root->last[i]=Root;
    while(!Q.empty())
    {
        Node *u=Q.front();Q.pop();
        if(u!=NULL)
        {
            Node *T=u;
            u->Val+=u->f->Val;
            for(int i=0;i<=26;i++)
                if(!u->ch[i])
                    u->last[i]=u->f->last[i];
                else
                    u->ch[i]->f=u->f->last[i],Q.push(u->last[i]=u->ch[i]);
        }
    }
}
A Dp;

void DFS(Node *Cur)
{
    if(!Cur)return;
    for(int i=0;i<27;i++)
        DFS(Cur->ch[i]);
    for(int i=0;i<27;i++)
        if(Cur->last[i])
            Max(Dp.a[Cur->last[i]->no][Cur->no],Cur->last[i]->Val);
}


int main()
{
    ll n,l;
    read(n),read(l);
    for(int i=1;i<=n;i++)read(Data[i]);
    for(int i=1;i<=n;i++)
        Add(i);
    BFS();
    Dp=A(size,size);
    DFS(Root);
    Dp=Pow(Dp,l);
    A ans(size,1);
    ans.a[0][0]=0;
    ans=Dp*ans;
    ll Aa=-1;
    for(int i=0;i<=size;i++)
        Max(Aa,ans.a[i][0]);
    cout<<Aa<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值