[CQOI2009]循环赛&&[HNOI2013]比赛——真是好题(差点没把我脑子烧坏…sd的无奈) 提前声明:感谢大佬看了他的题解后,我才恍然大悟 …好,先上题目 [CQOI2009]循环赛题目描述 原题传送门. n队伍比赛,每两支队伍比赛一次,平1胜3负0.给出队伍的最终得分,求多少种可能的分数表。 输入输出格式 输入格式:第一行包含一个正整数n,队伍的个数。第二行包含n个非负整数,即每支队伍的得分。 输出格式:输出仅一行,即可能的分数表数目。保证至少存在一个可能的分数表。 输入样例#1:6(换行) 5 6 7 7 8 8 输出样例#1:121 [HNOI2013]比赛题目描述 原题传送门. 沫沫非常喜欢看足球赛,但因为沉迷于射箭游戏,错过了最近的一次足球联赛。此次联 赛共N支球队参加,比赛规则如下: (1) 每两支球队之间踢一场比赛。 (2) 若平局,两支球队各得1分。(3) 否则胜利的球队得3分,败者不得分。 尽管非常遗憾没有观赏到精彩的比赛,但沫沫通过新闻知道了每只球队的最后总得分, 然后聪明的她想计算出有多少种可能的比赛过程。 但沫沫发现当球队较多时,计算工作量将非常大,所以这个任务就交给你了。请你计算 出可能的比赛过程的数目,由于答案可能很大,你只需要输出答案对10^9+7取模的结果 输入输出格式 输入格式:第一行是一个正整数N,表示一共有N支球队。 接下来一行N个非负整数,依次表示各队的最后总得分。 输入保证20%的数据满足N<=4,40%的数据满足N<=6,60%的数据满足N<=8,100%的数据 满足3<=N<=10且至少存在一组解。 输出格式:仅包含一个整数,表示答案对10^9+7取模的结果 输入样例#1:4(换行) 4 3 6 4 输出样例#1:3 题解 两题差不多,我就说说后面的那题——比赛 这题一看就是大法师(dfs),n<=10,很简单嘛,来个爆搜(呵呵,自找群殴)其实并不然(紫题啊老铁,而且我是蒟蒻中的蒟蒻),辣么…肯定要剪枝,思考一下 按爆搜的思想进行剪枝 显而易见,dfs函数(按我的想法)要模拟,不是真模拟,而是把函数参数按模拟的思想设置,dfs(int u,int v)表示当前搜到第u队和第v队比赛(互撸)同时tot[i]表示当前第i队的分数,s[i]表示第i队的最终得分,now[i] (1<=i<=n)表示当前的一队比完赛后各个队还有多少分数需要搜索sum表示所有队的总分; 然后显而易见 一个剪枝出来了:当前搜到第u队的分数tot[u]如果赢了后面的所有比赛都仍然达不第u队的最终得分s[u],干脆剪枝(这个剪枝的力度还是挺大的) 下面来看看这张图,看看有没有什么发现 emmm,你肯定能发现表的右上三角形与左下角是对称的,这就说明我们其实只需要搜索上面的三角,很简单吧 但如果我们往深处再想想,就能发现一个大secret——所有比赛的胜负平,是可以算出来的!其实就是解一个二元一次方程组,设胜x场,则负也是x,平局y场…可以列出方程: 联立①和②得x=sum-n(n-1),y=(sum-3x)/2; 所以又有一个剪枝:当前搜索的位置若x<=0时,就不能赢,若y<=0,就不能平局 不知道看到这个三角形和一行一行填表的方法,你们会不会(鬼畜)想到最后一个剪枝,一起大声念出来:记忆化搜索memorize search!那怎么jyh嘞,大佬给了我们一个完美(也许有更完美的,等待各位发现)的答案:hash。算出剩下的比赛的状态——比完第u队(即当前搜索的队伍)的所有比赛后各队剩下的分数——再用hash算出对应的hash值,简单点说就是给出一个状态,带入函数,算出函数值(实在不行就去看看别的大佬写的关于hash的博客)这样就不用反复搜索同一个问题,直接返回算过的值 好,大家看懂了吗?希望你看懂了,但看不懂也没关系(因为我写得渣),多看看题解,思考思考,一定能想明白(就像正在写这篇博客的蒟蒻一样) 代码(再次鸣谢