CodeForces - 697F Legen... AC自动机+快速幂

题目链接点这里

这题很好,很强大,做了一晚上。。。。

如果对这题毫无思路的,建议先坐下这道题。做完这道题,结合10^14的数据,应该可以想到本题也应该利用AC自动机构造状态转移矩阵,然后利用快速幂加速

不过这里的矩阵乘法定义为  M[i][j]=max(a[i][k]+b[k][i],M[i][j]);

#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<queue>
#include<string.h>
#include<cstring>
#include<vector>
#include<time.h>
#include<stdlib.h>
using namespace std;
#define INF 0x3f3f3f3f
#define INFLL 0x3f3f3f3f3f3f3f3f
#define FIN freopen("input.txt","r",stdin)
#define mem(x,y) memset(x,y,sizeof(x))
typedef unsigned long long ULL;
typedef long long LL;
#define MX 1111111
const LL p=10000000000;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<pair<int,int>,int> PIII;
typedef pair<int,int> PII;
int n;
LL l;
struct Matrix
{
    LL M[222][222],n;//改
    Matrix () {}
    Matrix(int _n,LL x)  //初始化
    {
        n=_n;
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++) M[i][j]=x;
    }
    Matrix operator *(const Matrix &a) const
    {
        Matrix ret=Matrix(n,-1);
        for(int i=0; i<n; i++)
            for(int k=0; k<n; k++)
                for(int j=0; j<n; j++)
                    ret.M[i][j]=max(ret.M[i][j],((a.M[i][k]!=-1&&M[k][j]!=-1)?a.M[i][k]+M[k][j]:-INF));
        return ret;
    }
};
Matrix pow_Matrix(Matrix a,LL x)
{
    Matrix ret=Matrix(a.n,0);
    // for(int i=0; i<a.n; i++) ret.M[i][i]=0;
    while(x)
    {
        if(x&1) ret=ret*a;
        a=a*a;
        x>>=1;
    }
    return ret;
}
char s[1000+10];
struct AC_trie
{
    int root,cnt;
    int End[5000+10],to[5000+10][27],fail[5000+10];//改
    int newnode()
    {
        for(int i=0; i<26; i++) to[cnt][i]=-1;//改
        End[cnt]=0;
        return cnt++;
    }
    void init()
    {
        cnt=0;
        root=newnode();
    }
    void insert(char *s,int w)
    {
        int now=root;
        for(char *ss=s; *ss; ss++)
        {
            int v=*ss-'a';//改
            if(to[now][v]==-1)to[now][v]=newnode();
            // cout<<*ss<<" "<<to[now][v]<<endl;
            now=to[now][v];

        }
        End[now]+=w;//改

    }
    void build()
    {
        queue<int> my;
        fail[root]=root;
        for(int i = 0; i < 26; i++)//改
            if(to[root][i] == -1)
                to[root][i]= root;
            else
            {
                fail[to[root][i]]=root;
                my.push(to[root][i]);
            }
        //
        while(!my.empty())
        {
            int u=my.front();
            End[u]+=End[fail[u]];
            //cout<<u<<" "<<fail[u]<<" "<<End[u]<<" "<<End[fail[u]]<<endl;
            my.pop();
            for(int i=0; i<26; i++)   //改
            {
                int v=to[u][i];
                if(v!=-1)
                {
                    fail[v]=to[fail[u]][i];
                    my.push(v);
                }
                else to[u][i]=to[fail[u]][i];
            }
        }
    }
    Matrix Matrix_build()
    {
        Matrix a=Matrix(cnt,-1);
        for(int i=0; i<cnt; i++)
            for(int j=0; j<26; j++) a.M[i][to[i][j]]=End[to[i][j]];
        return a;
    }
} AC;
int val[222];
int main()
{
    FIN;
    while(~scanf("%d%I64d",&n,&l))
    {
        AC.init();
        for(int i=1; i<=n; i++) scanf("%d",&val[i]);
        for(int i=1; i<=n; i++)
        {
            scanf("%s",s);
            AC.insert(s,val[i]);
        }
        AC.build();
        Matrix a=AC.Matrix_build();
        // for(int i=0; i<AC.cnt; i++)
        //   for(int j=0; j<AC.cnt; j++) printf("%I64d%c",a.M[i][j],j==AC.cnt-1?'\n':' ');
        Matrix b=pow_Matrix(a,l);
        // for(int i=0; i<AC.cnt; i++)
        //  for(int j=0; j<AC.cnt; j++) printf("%I64d%c",b.M[i][j],j==AC.cnt-1?'\n':' ');
        LL ans=0;
        for(int i=0; i<AC.cnt; i++)ans=max(ans,b.M[0][i]);
        printf("%I64d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值