• 洛谷 P3041 [USACO12JAN]Video Game G(AC自动机,dp)


    传送门


    解题思路

    先对所有的string跑一遍AC自动机。

    用sum表示到达一个节点的收益,可以在求fail时顺便继承着fail节点的sum值。

    然后在这个AC自动机上做dp即可。

    设dp[i][j]为第i步走到AC自动机上的j号节点的最大分数,枚举转移到的点数转移即可。

    AC代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    using namespace std;
    const int inf=1e9;
    const int maxn=1e3+5;
    int n,m,tr[305][5],ans,dp[maxn][305],tot,num[305],sum[305],fail[305];
    string s[30];
    void insert(string s){
    	int now=0,len=s.length();
    	for(int i=0;i<len;i++){
    		int k=s[i]-'A';
    		if(tr[now][k]) now=tr[now][k];
    		else tr[now][k]=++tot,now=tot;
    	}
    	sum[now]++;
    }
    void build(){
    	queue<int> q;
    	for(int i=0;i<3;i++){
    		if(tr[0][i]) q.push(tr[0][i]);
    	}
    	while(!q.empty()){
    		int now=q.front();q.pop();
    		for(int i=0;i<3;i++){
    			if(tr[now][i]) fail[tr[now][i]]=tr[fail[now]][i],q.push(tr[now][i]);
    			else tr[now][i]=tr[fail[now]][i];
    		}
    		sum[now]+=sum[fail[now]];
    	}
    }
    int main(){
    	//freopen(".in","r",stdin);
    	//freopen(".out","w",stdout);
    	ios::sync_with_stdio(false);
    	cin>>n>>m;
    	for(int i=1;i<=n;i++) cin>>s[i],insert(s[i]);
    	build();
    	for(int i=0;i<=m;i++){
    		for(int j=1;j<=tot;j++){
    			dp[i][j]=-inf;
    		}
    	}
    	for(int i=0;i<m;i++){
    		for(int j=0;j<=tot;j++){
    			for(int k=0;k<3;k++){
    				dp[i+1][tr[j][k]]=max(dp[i+1][tr[j][k]],dp[i][j]+sum[tr[j][k]]);
    			}
    		}
    	}
    	for(int i=0;i<=tot;i++){
    		ans=max(ans,dp[m][i]);
    	} 
    	cout<<ans; 
    	return 0;
    }
    
  • 相关阅读:
    c# 门禁随笔
    DataTable到Access
    C#文件上传
    C#操作文件
    JavaScript 全局封装
    jsavascript 目录的操作(摘抄)
    12-STM32 ADC原理
    11-STM32 高级定时器TIM1/8
    10-STM32 基本定时器TIM
    9-STM32 WWDG窗口看门狗
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15394736.html
Copyright © 2020-2023  润新知