Match:Censored!(AC自动机+DP+高精度)(POJ 1625)

            

                  Censored!

  题目大意:给定一些字符,将这些字符组成一个固定长度的字符串,但是字符串不能包含一些禁词,问你有多少种组合方式。

  这是一道好题,既然出现了“一些”禁词,那么这题肯定和AC自动机有点关系了,对于这一题来说,因为我们需要的是求出在N^M种状态除去包含禁词的状态数,枚举肯定是不现实的了,我们唯一能做的只能是DP,但是怎么DP呢?只能是通过AC自动机来想了,由此我们来看一下trie树,我们知道trie树是可以表示不同字符串前后缀的转移关系的,但是这一题并不是要我们求出字串中是否有禁词,而是要我们求出除了禁词的其他组合方式,那么我们可不可以通过trie树直接看出来呢?答案是可以的,但是我们要改进一下。

  如果我们把trie树中的Next数组补齐,比如在ACGT中含有禁词ACC,C,我们可以构建如下图的一个trie树

                

  

  我们可以看到这棵trie树补齐了一般trie树不存在的边,其实就是把不存在的对应k子节点指向当前节点的fail节点的k节点,这样我们就可以找到所有元素转移的状态关系了,得到了这个东西,那么我们就可以用DP来把状态转移全部搞出来了,组成一个m长度的单词,只要我们不从失败状态(禁词的结尾)转出或者转入就OK了。

  这样一开DP就很容易理解了,状态转移方程dp[i+1][转移状态]=dp[i][trie树上某个节点]+dp[i+1][转移状态](转移状态是指的是其他节点转移过来的情况),那么怎么标定非法情况呢?我们不仅要把单词结尾标记为非法状态,如果当前位置fail指针的指向的k位置也为单词结尾,那么当前位置的指向的k位置也必须标记为非法状态,因为我们不能从这个节点转出(也就意味着这个单词是包含着另一个单词的)。

  

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <functional>
  4 #define MAX 130
  5 
  6 using namespace std;
  7 
  8 static int sum_node, Hash_Table[MAX];
  9 static char str[200];
 10 
 11 struct node
 12 {
 13     int if_end,num;//注意end位置不仅是标记单词的结束,而且还表示了是否能状态转移
 14     node *fail, *Next[MAX];
 15 }Mem_Pool[MAX], *Trie_Node[MAX], *Queue[MAX * 2];
 16 struct BigInterget
 17 {
 18     int A[25];
 19     enum { MOD = 10000 };
 20     BigInterget()//构析函数用于初始化大数,A[0]表示大数的长度
 21     {    
 22         memset(A, 0, sizeof(A)); 
 23         A[0] = 1; 
 24     }
 25     void set(int x)//用于设定一个32位的整数
 26     { 
 27         memset(A, 0, sizeof(A));
 28         A[0] = 1; A[1] = x; 
 29     }
 30     void print(void)
 31     {
 32         printf("%d", A[A[0]]);
 33         for (int i = A[0] - 1; i > 0; i--)
 34         {
 35             if (A[i] == 0){ printf("0000"); continue; }
 36             for (int k = 10; k*A[i] < MOD; k *= 10)
 37                 printf("0");
 38             printf("%d", A[i]);
 39         }
 40         printf("\n");
 41     }
 42     int& operator [] (int pos) { return A[pos]; }
 43     const int& operator [] (int pos) const { return A[pos]; }
 44 
 45     BigInterget operator + (const BigInterget &B)
 46     {
 47         BigInterget C;
 48         C[0] = max(A[0], B[0]);
 49         for (int i = 1; i <= C[0]; i++)
 50             C[i] += A[i] + B[i], C[i + 1] += C[i] / MOD, C[i] %= MOD;
 51         if (C[C[0] + 1] > 0)C[0]++;//进位
 52         return C;
 53     }
 54 };
 55 static BigInterget dp[52][MAX];
 56 
 57 struct node *create_new_node(void);
 58 void put_letter_to_hash(const int);
 59 void Insert(struct node *);
 60 void build_ac_automation(struct node *);
 61 
 62 int main(void)
 63 {
 64     int Word_Length, Forbidden_Word_Sum, Letter_Type_Sum;
 65     while (~scanf("%d%d%d", &Letter_Type_Sum, &Word_Length, &Forbidden_Word_Sum))
 66     {
 67         sum_node = 0;
 68         memset(Hash_Table, 0, sizeof(Hash_Table));
 69         node *root = create_new_node();
 70         put_letter_to_hash(Letter_Type_Sum);
 71 
 72         for (int i = 0; i < Forbidden_Word_Sum; i++)
 73             Insert(root);
 74         build_ac_automation(root);
 75         
 76         for (int i = 0; i <= Word_Length; i++)
 77             for (int j = 0; j < sum_node; j++)
 78                 dp[i][j] = BigInterget();
 79         dp[0][0].set(1);
 80 
 81         for (int i = 0; i < Word_Length; i++)
 82             for (int j = 0; j < sum_node; j++)
 83             {
 84                 if (Mem_Pool[j].if_end)//不能从非法状态中转入
 85                     continue;
 86                 for (int k = 0; k < Letter_Type_Sum; k++)
 87                 {
 88                     if (Mem_Pool[j].Next[k]->if_end)//不能从非法状态中转出
 89                         continue;
 90                     int id = Mem_Pool[j].Next[k]->num;
 91                     dp[i + 1][id] = dp[i][j] + dp[i + 1][id];
 92                 }
 93             }
 94         BigInterget ans = BigInterget();
 95         for (int i = 0; i < sum_node; i++)
 96             ans = ans + dp[Word_Length][i];
 97         ans.print();
 98     }
 99     return EXIT_SUCCESS;
100 }
101 
102 struct node *create_new_node(void)
103 {
104     node *tmp = &Mem_Pool[sum_node];
105     tmp->fail = NULL;
106     tmp->if_end = 0;
107     tmp->num = sum_node++;
108     memset(tmp->Next, NULL, sizeof(struct node*)*MAX);
109     return tmp;
110 }
111 
112 void put_letter_to_hash(const int Letter_Type_Sum)
113 {
114     getchar();//去掉回车换行
115     gets(str);
116 
117     for (int i = 0; i < Letter_Type_Sum; i++)
118         Hash_Table[str[i]] = i;
119 }
120 
121 void Insert(struct node *root)
122 {
123     gets(str);
124     struct node *tmp_ptr = root;
125 
126     for (int i = 0; str[i] != '\0'; i++)
127     {
128         int id = Hash_Table[str[i]];
129         if (tmp_ptr->Next[id] == NULL)
130             tmp_ptr->Next[id] = create_new_node();
131         tmp_ptr = tmp_ptr->Next[id];
132     }
133     tmp_ptr->if_end = 1;
134 }
135 
136 void build_ac_automation(struct node *root)
137 {
138     int head = 0, tail = 0;
139     node *out = NULL;
140     root->fail = NULL;
141     Queue[tail++] = root;
142     
143     while (head != tail)
144     {
145         out = Queue[head++];
146         for (int i = 0; i < MAX; i++)
147             if (out->Next[i] != NULL)
148             {
149                 if (out == root)
150                     out->Next[i]->fail = root;
151                 else
152                 {
153                     out->Next[i]->fail = out->fail->Next[i];
154                     //如果还找到在其他地方找到和他一样的元素,那么我们就把失败指针指向这个元素,同时要设定合法状态
155                     out->Next[i]->if_end = out->fail->Next[i]->if_end ? 1 : out->Next[i]->if_end;
156                 }
157                 Queue[tail++] = out->Next[i];
158             }
159             else
160             {
161                 if (out == root) out->Next[i] = root;
162                 else out->Next[i] = out->fail->Next[i];
163             }
164     }
165 }

  另外这个题要用到大数加法,在网上找了个很好的模板,以后就用这个了

  

  参考:http://blog.csdn.net/AndyTeen/article/details/45668121

     http://blog.csdn.net/scut_pein/article/details/22204681

     http://www.cnblogs.com/laiba2004/p/4004417.html

转载于:https://www.cnblogs.com/Philip-Tell-Truth/p/5189842.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
健身国际俱乐部系统是一种专为健身俱乐部设计的管理软件,它通过集成多种功能来提高俱乐部的运营效率和服务质量。这类系统通常包含以下几个核心模块: 1. **会员管理**:系统能够记录会员的基本信息、会籍状态、健身历史和偏好,以及会员卡的使用情况。通过会员管理,俱乐部可以更好地了解会员需求,提供个性化服务,并提高会员满意度和忠诚度。 2. **课程预约**:会员可以通过系统预约健身课程,系统会提供课程时间、教练、地点等详细信息,并允许会员根据个人时间表进行预约。这有助于俱乐部合理安排课程,避免资源浪费。 3. **教练管理**:系统可以管理教练的个人信息、课程安排、会员反馈等,帮助俱乐部评估教练表现,优化教练团队。 4. **财务管理**:包括会员卡销售、课程费用、私教费用等财务活动的记录和管理,确保俱乐部的财务透明度和准确性。 5. **库存管理**:对于俱乐部内的商品销售,如健身装备、营养补充品等,系统能够进行库存管理,包括进货、销售、库存盘点等。 6. **数据分析**:系统能够收集和分析会员活动数据,为俱乐部提供业务洞察,帮助俱乐部制定更有效的营销策略和业务决策。 7. **在线互动**:一些系统还提供在线平台,让会员可以查看课程、预约私教、参与社区讨论等,增强会员之间的互动和俱乐部的社区感。 8. **移动应用**:随着移动设备的普及,一些健身俱乐部系统还提供移动应用,方便会员随时随地管理自己的健身计划。 9. **安全性**:系统会确保所有会员信息的安全,采取适当的数据加密和安全措施,保护会员隐私。 10. **可扩展性**:随着俱乐部业务的扩展,系统应该能够轻松添加新的功能和服务,以适应不断变化的市场需求。 健身国际俱乐部系统的选择和实施,需要考虑俱乐部的具体需求、预算和技术能力,以确保系统能够有效地支持俱乐部的运营和发展。通过这些系统的实施,健身俱乐部能够提供更加专业和高效的服务,吸引和保留更多的会员,从而在竞争激烈的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值