第一道AC自动机+DP,自己好菜连一个线性DP都不会,还得去看博客。
大佬 Orz <一蒟蒻(我)
题意:给你一个文本串,再给你几个单词,用单词组成文本串的方案数(单词不能重叠)。
我的思路:用AC自动机跑出文本串中出现单词区间[s,e](我的代码中的e表示单词结束位置的后一位,为了方便dp),
DP方程:dp[i]表示i到文本串结尾的方案数 dp[i]=sum{d[i+len(x)]|x是从i位置出现过的单词}
虽然这样能够,但是感觉写法很***。。。大佬是直接在树上DP。
大佬博客:https://www.cnblogs.com/candy99/p/5959943.html
我的***代码:
///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const int mod=20071027;
const int INF=0x3f3f3f3f;
struct node
{
node *child[26];
node *fail;
int sign;
};
node *root;
char word[105];
char text[300005];
int head[300005];
struct ANS
{
int e;
int pre;
}edge[2000005];
int sub;
void insert_word(char *s,int len)
{
node *now=root,*temp;
int x;
for(int i=0;s[i];i++)
{
x=s[i]-'a';
if(now->child[x]==NULL)
{
temp=new node();
temp->fail=NULL;
temp->sign=0;
memset(temp->child,NULL,sizeof(temp->child));
now->child[x]=temp;
}
now=now->child[x];
}
now->sign=len;
}
void build_fail()
{
queue<node *>q;
node *now,*temp;
q.push(root);
while(!q.empty())
{
now=q.front();
q.pop();
for(int i=0;i<=25;i++)
{
if(now->child[i])
{
if(now==root)
now->child[i]->fail=root;
else
{
temp=now->fail;
while(temp)
{
if(temp->child[i])
{
now->child[i]->fail=temp->child[i];
break;
}
temp=temp->fail;
}
if(temp==NULL)
now->child[i]->fail=root;
}
q.push(now->child[i]);
}
}
}
}
void add_edge(int s,int e)
{
edge[++sub]=ANS{e,head[s]};
head[s]=sub;
}
void ac_auto(char *s)
{
node *now=root,*temp;
int x;
for(int i=0;s[i];i++)
{
x=s[i]-'a';
while(now!=root&&now->child[x]==NULL)
now=now->fail;
now=now->child[x];
if(now==NULL)
now=root;
temp=now;
while(temp!=root)
{
if(temp->sign>0)
add_edge(i-(temp->sign)+1,i+1);
temp=temp->fail;
}
}
}
void init()
{
root->fail=NULL;
root->sign=0;
memset(root->child,NULL,sizeof(root->child));
}
int main()
{
int n,s,e,u=0;
int dp[300005];
root=new node();
while(scanf("%s",text)!=EOF)
{
init();
int d=strlen(text);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",word);
insert_word(word,strlen(word));
}
build_fail();
for(int i=0;i<d;i++)
{
head[i]=-1;
dp[i]=0;
}
dp[d]=1;
sub=0;
ac_auto(text);
for(int i=d-1;i>=0;i--)
{
for(int j=head[i];j!=-1;j=edge[j].pre)
{
s=i;
e=edge[j].e;
dp[s]=(dp[s]+dp[e])%mod;
}
}
printf("Case %d: %d\n",++u,dp[0]);
}
return 0;
}
照着大佬思路敲得代码:
///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const int mod=20071027;
const int INF=0x3f3f3f3f;
struct node
{
node *child[26];
node *fail;
int sign;
};
node *root;
char word[105];
char text[300005];
int dp[300005];
void insert_word(char *s)
{
node *now=root,*temp;
int x;
for(int i=0;s[i];i++)
{
x=s[i]-'a';
if(now->child[x]==NULL)
{
temp=new node();
temp->fail=NULL;
temp->sign=0;
memset(temp->child,NULL,sizeof(temp->child));
now->child[x]=temp;
}
now=now->child[x];
}
now->sign=1;
}
void find_dp(char *s,int d)
{
int x;
node *now;
for(int i=d-1;i>=0;i--)
{
now=root;
for(int j=i;j<=i+100-1&&j<d;j++)
{
x=s[j]-'a';
if(now->child[x]==NULL)
break;
now=now->child[x];
if(now->sign)
dp[i]=(dp[i]+dp[j+1])%mod;
}
}
}
void init()
{
root->fail=NULL;
root->sign=0;
memset(root->child,NULL,sizeof(root->child));
}
int main()
{
int n,u=0;
root=new node();
while(scanf("%s",text)!=EOF)
{
init();
int d=strlen(text);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",word);
insert_word(word);
}
for(int i=0;i<d;i++)
dp[i]=0;
dp[d]=1;
find_dp(text,d);
printf("Case %d: %d\n",++u,dp[0]);
}
return 0;
}