hdoj 2243
不仅仅是考研路茫茫 A此题的过程也是路茫茫 终于到最后柳暗花明了
A这个题用了3天 或者说用了1个月(因为1个月前就学了KMP和AC自动机)
虽然上个月那节课学了KMP匹配算法+字典树+AC自动机。 当时就听得一头雾水 特别是KMP那个失败指针(或者说成是next[] fail[]...)
有那么点点的抽象 听完之后的水平当然是非常烂 只能做一些模板题或者拿模板做做题 稍微变一下的问题就不会了 关键还是对算法理解不深 KMP都不会更不说AC自动机了
那节课后过了几天 遇到一场吉林大学主办的多校联赛 其中有一个题http://acm.jlu.edu.cn/joj/showproblem.php?pid=2754
旁边几个队过得很快 我们队题量少的弱点瞬间体现了出来 AC自动机不会啊(其实当时根本没意识到是AC自动机能解决的...)
然后此题终于A了 推了近4个小时的公式然后用矩阵加速过了 赛后听同学讨论AC自动机...什么 有AC自动机?
那个题也是因为当时推出公式 后面就没管了
最近重新粗浅地学了下字符串匹配 理解比以前当然要深些了 至少AC自动机构造了解了点嘛
说说这道题吧
这个题意是给出一个 n 和一个l
然后给出n个单词 求长度为l的小写字母串中至少包含n个单词中1个词的串的个数(好像有点点绕口)
地址在这里:http://acm.hdu.edu.cn/showproblem.php?pid=2243
"至少"这中词汇很敏感 可以从对立角度来想想.
就是先求出所有串的个数 然后减去一个单词都不包含的个数咯
所有串的个数就是26^1+26^2+...26^l次方
这个可以用一个函数写 这个多项式可以二分求解
我代码里是Sum(x,n)函数 求x^1+x^2+...x^n
至于求一个单词都不包含的串的个数
这个就可以用到AC自动机了 AC自动机构建矩阵!
我当时很纳闷 AC自动机不是解决字符串匹配的吗?(所以说不能老用模板A题,模板就是拿来匹配的)
然后就去找相关AC自动机构建矩阵的资料http://hi.baidu.com/%D2%D5%C1%D6010/blog/item/6db06ccf0a3b440993457e7b.html
这篇文章写得很好 我也很感谢他 求一个串中不包含单词的办法
看了上面那个 理解了很久 主要就是它那个矩阵 怎么ans+=matrix[0][i]就是最后的答案 而且关于矩阵的传递闭包没个概念
然后就经过了2天。。。(时间主要花在理解这个矩阵上面了)
尼玛的我终于搞懂了 我们构造矩阵的方式不一样 我的矩阵是转置后乘右边的一个nx1向量 他是不转置左边乘一个1xn向量
求一个固定长度l不包含任何单词的方法会了
只要理解了那个矩阵 hdu2243这个题就好办了 因为这题就加了一个求所有长度不包含然和单词的串
只需要包矩阵多加一行一列就行了
这个可以自己去理解构造
然后这题一直timelimit
我无语了 我试了很大的数据 20亿都是一瞬间出结果 再看人家交的代码都是15MS 这题也不卡时间啊
然后又纠结了一下午 然后就发现这题有个数据就是2^31-1
因为矩阵我自己加了一行一列 然后矩阵求冥就是求(l+1)次方
l我用的int 然后l+1 然后就溢出啦 然后死循环。。。
我怎么发现这个的?
因为2^31-2可以出数据 2^31-1 就不行了啊!!!!尼玛啊
改过就A了!
这个时间花长了 不过理解也深了 与其粗浅地学很多算法 不如深入地学一两个算法
最近不喜欢用Vc了 老死机 太烂的BUG啊 不过断点调试又要用它。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define KIND 26
#define MAXN 33
#define FF(i,n) for(i=0;i<n;i++)
typedef unsigned __int64 ULL;
struct IM
{
ULL el[MAXN][MAXN];
}sgl,bas;
int N;
IM operator * (IM &x,IM &y)
{
IM r;
int i,j,k;
FF(i,N)
FF(j,N)
r.el[i][j]=0;
FF(i,N)
FF(k,N)
if(x.el[i][k])
FF(j,N)
if(y.el[k][j])
r.el[i][j]+=x.el[i][k] * y.el[k][j];
return r;
}
IM operator ^ (IM x,ULL m)
{
IM r=sgl;
for(;m;m>>=1)
{
if(m&1)
r=r*x;
x=x*x;
}
return r;
}
struct Node
{
int fail;
bool end;
int next[KIND];
void init()
{
fail=-1;
end=0;
memset(next,-1,sizeof(next));
}
}node[MAXN];
int q[MAXN<<1];
int head,tail;
int sz;
void init()
{
sz=0;
node[0].init();
}
void Insert(char *str)
{
int p=0;
for(int i=0;str[i];i++)
{
if(node[p].end)
break;
int index=str[i]-'a';
if(node[p].next[index]==-1)
{
node[p].next[index]=++sz;
node[sz].init();
}
p=node[p].next[index];
}
node[p].end=1;
}
void Build_AC()
{
int temp;
int p=0;
head=tail=0;
q[tail++]=p;
while(head<tail)
{
temp=q[head++];
for(int i=0;i<KIND;i++)
{
p=node[temp].next[i];
if(p!=-1)
{
if(!temp)
node[p].fail=0;
else
{
node[p].fail=node[node[temp].fail].next[i];
if(node[node[p].fail].end)
node[p].end=1;
}
q[tail++]=p;
}
else
{
if(!temp)
node[temp].next[i]=0;
else
node[temp].next[i]=node[node[temp].fail].next[i];
}
}
}
}
ULL power(ULL a,int n)
{
ULL ret;
for(ret=1;n;n>>=1)
{
if(n & 1)
ret*=a;
a*=a;
}
return ret;
}
ULL Sum(ULL x,int n)
{
if(n==1)
return x;
if(n & 1)
return Sum(x,n>>1)*(power(x,(n>>1)+1)+1)+power(x,(n>>1)+1);
return Sum(x,n>>1)*(power(x,n>>1)+1);
}
int main()
{
int n;
ULL l;
char words[11];
while(~scanf("%d %I64u",&n,&l))
{
init();
for(int i=1;i<=n;i++)
{
scanf("%s",words);
Insert(words);
}
Build_AC();
sz+=2;
N=sz;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
{
bas.el[i][j]=0;
sgl.el[i][j]=(i==j);
}
for(int i=0;i<sz-1;i++)
{
if(!node[i].end)
for(int j=0;j<KIND;j++)
if(!node[node[i].next[j]].end)
bas.el[node[i].next[j]][i]++;
}
for(int i=0;i<N;i++)
bas.el[N-1][i]=1;
/*
for(i=0;i<N;i++)
{
for(int j=0;j<N;j++)
printf("%I64u ",bas.el[i][j]);
puts("");
}
*/
IM mat=bas^(l+1);
ULL s=mat.el[N-1][0]-1;
ULL top=Sum(26,l);
ULL ans=top-s;
if(ans<0)
ans=ans+((ULL)1<<63)+((ULL)1<<63);
printf("%I64u\n",ans);
}
return 0;
}