USACO2014Open Gold Code Breaking

Task:
The cows keep getting in trouble by taking rides on Farmer John’s tractor,
so he has hidden the keys to the tractor in a fancy new safe in his
office. Undeterred, the cows have vowed to try and break into this safe.
The safe is protected by a rather complicated passcode system. The passcode
entry system is arranged as a rooted tree of N (1 <= N <= 20,000) nodes,
each of which requires a digit between 0 and 9. The nodes are indexed 0..N-1.
The only information that the cows have is that certain sequences of length
5 do not occur along particular paths upwards through the tree.
For instance, suppose the tree is the following (rooted at A):
A <- B <- C <- D <- E
^
|
F
The cows might know that the sequence 01234 does not occur starting at F,
and that the sequence 91234 does not occur starting at E. This information
rules out 19 possible passcodes: all those of the form
4 <- 3 <- 2 <- 1 <- *
^
|
0
or
4 <- 3 <- 2 <- 1 <- 9
^
|
*
which gives 19 once we account for the fact that
4 <- 3 <- 2 <- 1 <- 9
^
|
0
appears twice.
Given M (1 <= M <= 50,000) length-5 sequences, together with their starting
nodes in the tree, help the cows figure out how many passcodes have been
ruled out. You should compute your answer modulo 1234567.

SAMPLE INPUT
6 2
0
1
2
3
3
4 01234
5 91234

SAMPLE OUTPUT
19

Solution:首先我们可以很快看出这道题目是一个树形dp题,其次我们可以知道,我们要先求不存在非法方案的个数,再用总方案去减它,因为这显然比直接求非法方案总数要简单.

我们可以先定义dp[i][j]为以i为根,且i上面4个节点组成的数字为j时的方案总数,再去枚举i放什么,这样就能开始dp了,但是这样做的空间与时间复杂度过大,首先你要开一个2亿的数组,以及一个20亿的枚举.显然是不行的.

那么我们可以发现什么?如果上面传来的数字在下面的非法条件(每个截取一部分)中没有出现过,那么它和没有传下来是一样的,我们通过这个可以将0变成1,把1变成2…来使它们有一个共同的数字,来表示没有数字传下来,也就是我们把它们都转化为16进制,然后就有‘0’来表示这个没有用的数字了.

然后我们把每个非法方案的每一部分(一个个删除了第一位数字后)存到相应的节点里,因为只有这一部份的dp才有用,其他的就相当于‘0’了.

这样的话,我们所要算的dp值已经少了很多,但我们还要去优化求dp值的过程.

如果这个节点下面的节点都没有出现过某种排列,那么它也不会有用了(也就是之前说的0),同时,如果一个排列的末尾一段在下面节点出现过,那么它的dp值就是最长的匹配的子排列的dp值.而这两种在枚举的时候可以一起算.

而每一个dp值就是所有儿子可能性的积,有些可能只有一部分不同,大部分还是相同的,所以这里还可以用线段树来优化,每一次求只更新lognlogn个节点,每次取SegTree[1]表示所有可能的乘积,而因为每一种dp都要取它们儿子中的它的子集的乘积,所以这也可以看作是一个树形的结构,每个dp指向它的一个最接近的子集,在求完后还原线段树并返回去就行了,那么就能知道所有的dp最终都会指向‘0’这个子集,所以求的时候直接从‘0’开始就行了.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<v
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值