HDU 3724 Encoded Barcodes (2010 Asia Tianjin Regional Contest )

【题目链接】http://acm.hdu.edu.cn/showproblem.php?pid=3724

【解题报告】
trie树基础题。建立静态trie树,然后查找即可。有两个要点。

1.如何确定某个前缀覆盖了多少个单词。
很简单,我们每插入一个单词的时候,在它走过的路径上所有结点权值加1,即表示当前结点被覆盖过多少次。那么我们查找前缀的时候,前缀的最后一个字母落在哪一个节点上,返回该点权值即可。

2.如何把一个barcode转化为二进制数。
对于读入的8个数,找到最大数max_num,那么和他一样在二进制数位中表示为1的那些数A[i],满足这样一个关系:fabs(max_num-A[i])/max_num<0.1.(注意为了防止某些坑点,最好加上一个eps精度控制)

这道题目我MLE&RE了十几发。开始我不加思考的算出最多会有30*1e5个节点,所以数组直接开超内存了(根据trie树的特点,一定会有大量单词覆盖相同节点,如果不是特意卡内存显然不需要开这么大…),改完之后提交又RE,误以为是空间开小了然后就纠结…最后发现,因为我在进行prefix查找的时候,是一边读入prefix一边遍历trie树,当trie树不存在这样一个prefix的时候,直接return 0,这样导致可能还有部分数据没有读入,于是就RE了….查这个错误查了好久好久,如果不犯懒老老实实写几组数据测一测应该可以避免这样额外的时间开支。

【参考代码】

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int eps=1e-6;
const int maxnode=2*1e5+50;
const int bit[9]={0,128,64,32,16,8,4,2,1 };
int barcode[9];

struct TRIE{
    int ch[maxnode][26];
    int val[maxnode];
    int sz;
    void clr(){  sz=1; memset(ch,0,sizeof(ch)); memset(val,0,sizeof(val)); }
    int idx(char c ){ return c-'a'; }
    int read()
    {
        float num[9];
        float max_num=0;
        for( int j=1; j<=8; j++ )
        {
            scanf("%f",&num[j]);
            if(num[j]-max_num>eps)max_num=num[j];
        }
        for( int j=1; j<=8; j++ )
        {
            if( fabs(num[j]-max_num)/max_num-0.1<eps )barcode[j]=1;
            else barcode[j]=0;
        }
        int c=0;
        for( int j=1; j<=8; j++ )c+=barcode[j]*bit[j];
        return c;
    }

    void ins( char* S )
    {
        int u=0,L=strlen(S);
        for( int i=0; i<L; i++ )
        {
            int c=idx(S[i]);
            if( !ch[u][c] )
            {
                ch[u][c]=sz++;
            }
            val[ch[u][c]]++;
            u=ch[u][c];
        }
    }

    int find_pre( int K )
    {
        int u=0;
        bool ok=true;
        for( int i=1; i<=K; i++ )
        {
            int c=read()-97;
            if(!ch[u][c]) ok=false;
            u=ch[u][c];
        }
        if(ok)return val[u];
        else return 0;
    }

}trie;


int main()
{
    int N,M,K;
    while(~scanf( "%d%d",&N,&M ))
    {
        trie.clr();
        int ans=0;
        for( int i=1; i<=N; i++ )
        {
            char name[40];
            scanf("%s",name);
            trie.ins( name );
        }
        for( int i=1; i<=M; i++ )
        {
            scanf("%d",&K );
            ans+=trie.find_pre( K );
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值