之前怎么写都是WA,空了一天写还是WA,把cin和cout都换成scanf和printf就过,奇怪的问题
定义状态dp[i]表示选择第i个串的最大价值
状态转移方程就是 dp[i]=max{dp[j]}+value[i],其中要求0<=j<i,且串j是串i的子串
因此问题就归结于高效判断子串的问题,这要求我们把每一个串都保存下来,当然,你记录每个点的father也行
然后每次对于串i,就在AC自动机上扫它的子串
代码里rec[i]表示第i个串的最后一个字符在AC自动机上的节点位置
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxm=3E5+5;
int times,ans,kcase,sz,root,n,ch[maxm][26],fail[maxm],last[maxm],dp[maxm],v[maxm],rec[20005],val[20005],pos[20005],newnode();
char str[maxm];
void getfail(),ins(int k),init();
int main(){
// ios_base::sync_with_stdio(false);
scanf("%d",×);
while(times--){
scanf("%d",&n);
//cin>>n;
init();
for(int i=0;i<n;++i){
scanf("%s%d",str+pos[i],&val[i]);
pos[i+1]=pos[i]+strlen(str+pos[i]);
//cin>>str[i];
ins(i);
//cin>>val[i];
}
getfail();
for(int i=0,u=root,p;i<n;++i,u=root)
if(val[i]>0){
for(int j=pos[i];j<pos[i+1];++j){
p=u=ch[u][str[j]];
if(!v[p]&&last[p]!=root)
p=last[p];
while(v[p]){
dp[rec[i]]=max(dp[rec[i]],dp[p]);
p=last[p];
}
}
dp[rec[i]]+=val[i];
ans=max(ans,dp[rec[i]]);
}
// for(int i=0;i<n;++i)
// cout<<dp[rec[i]]<<' ';
printf("Case #%d: %d\n",++kcase,ans);
// cout<<"Case #"<<++kcase<<": "<<ans<<endl;
}
return 0;
}
void init(){
sz=ans=0;
root=newnode();
}
void ins(int k){
int u=root;
for(int i=pos[k];str[i];++i){
str[i]-='a';
if(ch[u][str[i]]==root)
ch[u][str[i]]=newnode();
u=ch[u][str[i]];
}
v[u]=1;
rec[k]=u;
}
void getfail(){
queue<int> q;
for(int i=0;i<26;++i)
if(ch[root][i]!=root){
q.push(ch[root][i]);
fail[ch[root][i]]=last[ch[root][i]]=root;
}
int u;
while(!q.empty()){
u=q.front();q.pop();
for(int i=0;i<26;++i)
if(ch[u][i]==root)
ch[u][i]=ch[fail[u]][i];
else{
fail[ch[u][i]]=ch[fail[u]][i];
last[ch[u][i]]=(v[fail[ch[u][i]]]?fail[ch[u][i]]:last[fail[ch[u][i]]]);
q.push(ch[u][i]);
}
}
}
int newnode(){
dp[sz]=v[sz]=0;
memset(ch[sz],0,sizeof ch[sz]);
return sz++;
}