洛谷P3401 [USACO12JAN]Video Game G(AC自动机+记忆化搜索)
题目链接:https://www.luogu.com.cn/problem/P3041
无关的话:最近在学AC自动机,感觉很多AC自动机和矩阵快速幂以及dp有关系。那些板子题其实对板子的要求还是很高的,我听说指针版AC自动机会快一些,奈何我不会指针,就自己瞎凑了一个板子出来。以前听学长说有些东西只有0次和N次,我今天第一次接触面向对象保存板子,发现真的好用。以后遇到数据机构我都用面向对象封装模板了。
题解:
- 在AC自动机上如果一个点表示一个字符串以及它的后缀,则一个点可以对应多个combo技能(这是关键点)
- 可以先用拓扑排序处理出每个点对应了多少个combo技能,处理时要用fail的反向边即refail计算入度(这里应该不用这么麻烦,build的时候就可以直接加上去了)
- 然后就是记忆化搜索啦,这题没啥坑点。
- 我的板子tot最后需要减个1(因为实际上是每次我都预处理的)
AC代码:
#include<bits/stdc++.h> #pragma GCC optimize(2) #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; int n,k; int indeg[1005]; vector<int> refail[1005]; class ac_auto{ public: const static int maxn=5e4+100; int tot,root; int tree[maxn][5]; int num[maxn]; int fail[maxn]; int newnode(){ for(int i=0;i<3;i++){ tree[tot][i]=0; } num[tot]=0; return tot++; } void init(){ tot=0; root=newnode(); } void insert_(string s){ int now = root; for(int i=0;i<s.length();i++){ int id=s[i]-'A'; if(!tree[now][id]){ tree[now][id]=newnode(); } now=tree[now][id]; } num[now]++; } void getFail(){ queue <int>q; for(int i=0;i<3;i++){ if(tree[0][i]){ fail[tree[0][i]] = 0; q.push(tree[0][i]); } } while(!q.empty()){ int now = q.front(); q.pop(); for(int i=0;i<3;i++){ if(tree[now][i]){ fail[tree[now][i]] = tree[fail[now]][i]; refail[tree[fail[now]][i]].pb(tree[now][i]); indeg[tree[now][i]]++; q.push(tree[now][i]); } else tree[now][i] = tree[fail[now]][i]; } } } }acam; void toposort(){ queue<int> q; for(int i=0;i<acam.tot;i++){ if(!indeg[i]) q.push(i); } while(!q.empty()){ int now=q.front();q.pop(); for(auto v:refail[now]){ acam.num[v]+=acam.num[now]; if(--indeg[v]==0) q.push(v); } } } int dp[1010][410]; int dfs(int pos,int now){ if(pos>k) return 0; if(dp[pos][now]) return dp[pos][now]; int ans=0; rep(i,0,2){ ans=max(ans,acam.num[acam.tree[now][i]]+dfs(pos+1,acam.tree[now][i])); } return dp[pos][now]=ans; } int main(){ cin>>n>>k; acam.init(); rep(i,1,n){ string s;cin>>s; acam.insert_(s); } acam.getFail(); toposort(); cout<<dfs(1,0)<<endl; }
前ICPC算法竞赛退役选手|现摸鱼ing