先用resources和virus构造出AC自动机..
本题最暴力的状态是很好想到的...dp[a][b][c]...代表a长度时某串后缀能到AC自动机点b..能得到c些resources..其中c是一个用十进制表示的二进制数..代表题目里最多10个resources的存在情况...可见此种dp..状态最多可为10000*60000*1024...爆空间爆时间..各种爆..爆得体无完肤!!..
根据sha崽的提示..本题AC自动机里虽然点很多..但实际在更新转移中存在意义的点只有包含了resources的后缀点..而这些点的个数只有不超过50个..so..将这些后缀点之间的最短路径算出来...我就是直接枚举每个点BFS的...然后直接对这些存在转移意义的后缀点DP..瞬间时间和空间爆降阿..
正如HDOJ本题Dicuss里有人说的..本题数据还是很弱的..我找了好多网上发布的AC代码...没有一个代码能够跑出完全正确的结果..错得最多的是Discuss里的:
3 3
0001
0000
10000
010
101
111
好不容易找到这个数据能过的..结果又一大堆没考虑resources相同的..还有一些连手算的简单数据都出错..这道题数据的不严谨.众AC代码漏洞百出.真是奇葩.
我WA了十多次的原因是因为..白痴了..一个赋初值的地方没注意到要清0..结果..WA得想吐..
Program:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#define oo 2000000000
#define ll long long
using namespace std;
struct node
{
int son[2],fail,d,n;
bool w;
}point[60005];
int n,m,_2jie[12],dis[55][55],dp[55][1026],useful[55];
char s[50005];
queue<int> myqueue;
int used[60005];
int main()
{
int len,i,j,x,h,k,num,ans,goal;
_2jie[0]=1;
for (i=1;i<=10;i++) _2jie[i]=_2jie[i-1]*2;
while (~scanf("%d%d",&n,&m))
{
if (!n && !m) break;
memset(point,0,sizeof(point));
num=0;
for (j=0;j<n;j++)
{
scanf("%s",s);
len=strlen(s);
h=0;
for (i=0;i<len;i++)
{
if (!point[h].son[s[i]-'0'])
point[h].son[s[i]-'0']=++num;
h=point[h].son[s[i]-'0'];
}
point[h].d+=_2jie[j];
}
while (m--)
{
scanf("%s",s);
len=strlen(s);
h=0;
for (i=0;i<len;i++)
{
if (!point[h].son[s[i]-'0'])
point[h].son[s[i]-'0']=++num;
h=point[h].son[s[i]-'0'];
if (point[h].w) break;
}
point[h].w=true;
}
while (!myqueue.empty()) myqueue.pop();
for (i=0;i<2;i++)
if (point[0].son[i]) myqueue.push(point[0].son[i]);
num=1;
point[0].n=1;
useful[1]=0;
while (!myqueue.empty())
{
h=myqueue.front();
myqueue.pop();
if (point[point[h].fail].w) point[h].w=true;
if (point[h].w) continue;
point[h].d|=point[point[h].fail].d;
if (point[h].d)
{
point[h].n=++num;
useful[num]=h;
}
for (i=0;i<2;i++)
{
k=point[h].fail;
while (k && !point[k].son[i]) k=point[k].fail;
point[point[h].son[i]].fail=point[k].son[i];
if (!point[h].son[i])
point[h].son[i]=point[k].son[i];
else
myqueue.push(point[h].son[i]);
}
}
memset(dis,0,sizeof(dis));
for (i=1;i<=num;i++)
{
memset(used,0,sizeof(used));
myqueue.push(useful[i]);
used[useful[i]]=1;
while (!myqueue.empty())
{
h=myqueue.front();
myqueue.pop();
if (point[h].w) continue;
if (point[h].n) dis[i][point[h].n]=used[h]-1;
for (j=0;j<2;j++)
if (!used[point[h].son[j]])
{
used[point[h].son[j]]=used[h]+1;
myqueue.push(point[h].son[j]);
}
}
}
goal=_2jie[n]-1;
memset(dp,0,sizeof(dp));
dp[1][0]=1;
while (n--)
{
for (i=1;i<=num;i++)
for (k=0;k<goal;k++)
if (dp[i][k])
for (j=1;j<=num;j++)
if (dis[i][j])
{
x=k|point[useful[j]].d;
if (!dp[j][x] || dp[j][x]>dp[i][k]+dis[i][j])
dp[j][x]=dp[i][k]+dis[i][j];
}
}
ans=oo;
for (i=1;i<=num;i++)
if (dp[i][goal] && dp[i][goal]<ans) ans=dp[i][goal];
printf("%d\n",ans-1);
}
return 0;
}