- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
原创题目讲解;《WordCraft》是一个双人游戏。
游戏的唯一参数是一个字符串集D。
双方轮流进行。
轮到某玩家,他必须进行操作:
选择D中的一个串s,将D中所有s的前缀(包含s)删除。
不能操作就输了!
;该游戏一定会结束,因为每次操作D中的字符串数至少减1。
当轮到玩家,此时D是空集,那他就输了。
;如何解决?
最基本的方法:博弈树?
可行吗?
例子:{“a”,“abc”,“b”}
状态过多:O(2^N)
;为何状态过多?
因为没有充分利用题目条件!
题目中的关键字:“前缀”。
这让我们想到了树结构。
例:{“a”,“aa”,“ac”,“acg”,“acm”};这样,每次操作就变成:
选择某一结点,删除该结点到根的路径上的所有节点。
比如,上例中,可以进行的所有操作之后的局面:
;这样,一个局面可以看作是若干个树组成。
注意到所有操作只对其中的一棵树进行,与其他树无关。
这让我们联想到游戏的和。
我们要利用SG函数来求解。;分析:如果我们能够求出任何局面的SG值,那么我们就能知道初始的局面先手是否有必胜策略。以及,先手第一步应当如何走。
例子: SG = 1 xor 3 xor 2 = 0 所以,必败!;所以,本题可分为如下部分求解:
一、建树
二、求解SG值
三、输出解;需要建的是什么树?
每个结点的父亲是它的(除了它自己外)最长的前缀。
最基本算法:
O(N^2maxLen):对于每个结点,遍历集合D,找到这样的父亲。
怎么优化?
利用字典序;每个字符串的父亲如何找?
不妨令D[0] = “” :
void Find_Father(int i)
{
int j =i-1;
while(D[j]不是D[i]的前缀)
j = father[j];
father[i] = j;
};复杂度是多少?
j = father[j] 最多进行 maxLen 次。
每次判断前缀关系要O(maxLen)
一共是O(NmaxLen^2)
优化?
判断前缀关系的优化:
计算D[i]与D[i-1]的公共前缀长度comLen即可。
之后,D[j]是D[i]的前缀当且仅当 D[j].length() Len
这样,复杂度是O(NmaxLen);从底向上依次求解。
在求解某结点i时:
枚举所有可能的操作 O(N)
计算操走后的局面的SG值 O(N)
需要预处理:每个结点的所有儿子的SG值NIM和。(xor)
所以,总复杂度是O(N^3)?
枚举所有操作时进行一次DFS,遍历时顺带计算出SG值。
??间复杂度O(N^2);注意到这样的事实:
一个结点i为根的子树,一次操作后局面的SG值不可能大于该子树的结点数目。
重新计算复杂度:
O(NmaxLen);事实上,还有一种对于每个结点不再进行一次DFS的解法。
因为从一个结点DFS,这个过程其实在从它的儿子进行DFS时完成了。
时间关系先不讲了,论文里有详细介绍。
复杂度仍然是O(NmaxLen);显然,我们进行一次DFS就可以把所有的第一步可以取的字符串列举出。
现在的问题是:
给定n个字符串,请你按某顺序将所有的串连接起来,输出字典序最小的。
比如:串“ab”,“b”,我们可以连接得到
“abb”和“bab”,我们取前者。
这道题是我很久以前想到的。
后来我发现,这道题是NOIp1998提高组第二题!!;解法就是排序,不是按照字典序排,而是:
对于两串,比较谁排在前面的时候这两个串连接起来的字典序更小。
int cmp(const void *a,const void *b)
{
string A = *(string*)a , B = *(string*)b;
if( A+B B+A)
return -1;
else
return 1;
}
;请大家自己证明正确性。
特别地,如果这些串中没有一个是另外一个的子串,这个比较等价于比较字典序。
所以,按字典序输出即可。
我们并不需要再排序了,因为DFS时的遍历顺序就是字典序,前提是建树时按顺序来。
时间复杂度:O(NmaxLen);至此,三部分都被我们解决了!!
而给出的最优解的时间复杂度都是O(NmaxLen)。
这不可能更优,因为输入输出的复杂度和这一样。
在时间复杂度方面,完美解决啦~ ?;最初的题目是我学完SG函数的时候想到的:
给定一棵二叉树,初始时,所有结点是白的,双方轮流操作,每次选一个白结点,将该结点到根的路径上的所有结点涂黑。如果一个人无法操作,他就输了。
;之后,想到字符串的前缀关系就是一棵树,于是,题目描述就变成现在的样子了。
最后,我又想到了那道我出的、NOIp的题目
于是在输出解的时候加上了它。
题目的模型就全部完成。
题目描述用了OI界知名的FJ的奶牛故事。
至此,题面就全都完成了。;考查
原创力文档


文档评论(0)