HDU2825

解题思路:

首先按照正常的思路将自动机模型建立起来。

然后就在上面进行DP其中DP[i][j][k].i表示字符串的字符的个数j表示的是最后一位是什么状态.k表示magic string的状态这是用状态压缩记录的也就是2^10。通过每一位01表示该个magic string是否被表示。


这道题开始的时候是TLE,是memset的问题。改了之后就狂WA。后来找到了WA的原因,但是没有办法改。因为对于3 2 2 she he这样的数据没有办法过。最开始的想法是将状态之间的关系记录在g[maxn][maxn] 。然后每次加入一个状态就判断这个状态表示的字符串是否为magic string 如果是 则记录。但是后来发现这样写会有一个很严峻的问题。比如she he 那样的例子就不能得到解。后来看了其他人的代码。发现他们对于每一个状态就加入了tag数组,记录该状态下的字符串包含多少的magic string。

上代码:



#include<cstdio>
#include<cstring>
using namespace std;
struct node{
    node *fail;
    node *next[26];
    int count;
    int id;
    bool end;
    int tag;
    node(){
        id=0;
        end=false;
        fail=NULL;
        count=0;
        tag=0;
        for(int i=0;i<=25;i++){
            next[i]=NULL;
        }
    }
};
const int  MAXN=110;
node *T[110];
node *q[500010];
node *root=new node();
int num=1;
void insert(char word[],int pp){
    node *cur=root;
    int i=0,branch;
    while(word[i]){
        branch=word[i]-'a';
        if(cur->next[branch]==NULL){
            cur->next[branch]=new node();
            T[num]=cur->next[branch];
            cur->next[branch]->id=num++;
        }
        i++;
        cur=cur->next[branch];
    }
    cur->end=true;
    cur->count++;
    cur->tag=1<<pp;
}
void AC(){
    int rear=1,front=0,i;
    node *cur;
    q[0]=root;
    root->fail=root;
    while(front!=rear){
        node *p=q[front++];
        p->end=p->end||p->fail->end;
        for(int i=0;i<=25;i++){
            if(p->next[i]==NULL){
                if(p==root)
                    p->next[i]=root;
                else
                    p->next[i]=p->fail->next[i];
            }
            else{
                if(p==root)
                    p->next[i]->fail=root;
                else{
                    p->next[i]->fail=p->fail->next[i];
                    p->next[i]->tag=p->next[i]->tag|p->fail->next[i]->tag;
                }
                q[rear++]=p->next[i];
            }
        }
    }
}
int magic[110],g[MAXN][MAXN];
int nnum=0;
void get_matrix(){
    int i,j;
    memset(g,0,sizeof(g));
    memset(magic,0,sizeof(magic));
    for(int i=0;i<num;i++){
        for(int j=0;j<=25;j++){
            if(T[i]->next[j]!=NULL)
                g[i][T[i]->next[j]->id]++;


        }
        if(T[i]->end==true){
            magic[i]=++nnum;
        }
    }
}
int dp[30][110][1300];
int f[20];
void ini(){
    f[0]=1;
    for(int i=1;i<=10;i++){
        f[i]=2*f[i-1];
    }
}
int mod=20090717;
int gg[MAXN][MAXN];
main(){
    int n,m,kk;
    char s[20];
    while(scanf("%d%d%d",&n,&m,&kk)!=-1 && !(n==0 && m==0 && kk==0)){
        num=1;nnum=0;root=new node();
    for(int i=1;i<=m;i++){
        scanf("%s",s);
        insert(s,i-1);
    }
    AC();
    T[0]=root;
    root->id=0;
    get_matrix();
    for(int i=0;i<=n;i++)
        for(int j=0;j<=num;j++)
            for(int k=0;k<=1024;k++)
                dp[i][j][k]=0;
    ini();
   dp[0][0][0]=1;
    for(int i=0;i<num;i++){
        gg[i][0]=0;
        for(int j=0;j<num;j++){
            if(g[i][j]!=0){
                gg[i][++gg[i][0]]=j;
            }
        }
    }
    for(int i=0;i<=n-1;i++){
        for(int j=0;j<num;j++){
                for(int k=0;k<=1023;k++){
                    if(dp[i][j][k]!=0){
                        for(int x=1;x<=gg[j][0];x++){
                            int cnt=T[gg[j][x]]->tag;
                            dp[i+1][gg[j][x]][k|cnt]+=(dp[i][j][k]*g[j][gg[j][x]])%mod;
                            dp[i+1][gg[j][x]][k|cnt]=dp[i+1][gg[j][x]][k|cnt]%mod;
                        }
                    }
                }
        }
    }
    int ans=0;
    for(int i=0;i<num;i++){
        for(int j=0;j<=1023;j++){
            int flag=0;
            for(int k=0;k<=9;k++){
                int tmp=f[k]|j;
                if(tmp==j)
                    flag++;
            }
            if(flag>=kk && dp[n][i][j]!=0){
                ans+=dp[n][i][j];
                ans=ans%mod;
            }
        }
    }
    printf("%d\n",ans%mod);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值