USTCOJ 1388 钻石
来源:互联网 发布:淘宝利润计算 编辑:程序博客网 时间:2024/03/29 15:50
这道题是一道原创的数学题,我的思路是直接算出询问点处的概率概率,仅供大家参考。
题目链接:http://acm.ustc.edu.cn/ustcoj/problem.php?id=1388
经过分析:不难得出,钻石下落后的行为是堆成一个小三角形,然后往两边继续堆,堆至最高点又形成一个稍大的三角形,然后继续往两边堆,如此往复.
因此,我们得出结论,对于n颗钻石堆成的一个小三角形加他的两个边,这样的钻石结构,如果询问点在小三角形内,概率p = 1;如果询问点在两边上,则需要特殊对待,
利用数学方法求得概率,而不符合以上两种的点,概率p = 0;
关键难点在于询问点在两边上的位置时的概率计算.(一开始曾考虑递归计算,后来发现写出来非常麻烦,wa了以后无法调试,就放弃了);
Step1:
我们先考虑两种简单情况,最后来解决数学问题.
显然如果钻石数是1, 6, 15, 28.....则恰好构成三角形,没有多余,判断点是否在三角形内也十分简单,
我们假设由这n颗钻石堆成的三角形底边是len,表示有len颗钻石,而不是表示长度,(len为奇数,1, 3, 5, 7...),虽然有可能出现如下图的情况:
但我还是把他当做底边为1的三角形和他的两条边来处理,而不是底边为2, 总之把对称轴放在钻石下落的线上好处理
那么底边为len的三角形,,最高处的钻石的高度坐标为len - 1,判断是否在三角形内只需要判断表达式:abs(x) + y < len - 1成立即可;
显然两边上的点,x,y满足abs(x) + y == len - 1,内部小于.
所以我们一起解决了,在三角形内,三角形外的两种情况.
Step2:
接下来算点在两边上的概率;
这时由于n的大小改变,我们易想到,如果n除了用于堆中间三角形的钻石,剩下的钻石还比较多的话,把一条边堆满了,剩下钻石就只会往另一边堆,
这是不是等概率的,而在那之前都是等概率,所以我们把这两种情况分开计算,
先判断是否能把一条边堆满(堆满是指:底边长有len的三角形,边上有len+1颗钻石,例如上图中,左边的边就被堆满了,这以后只能往右边落)
一共有n颗钻石,堆三角形用了(len + 1) * len / 2颗,剩下的即为两者之差d,差d和len + 1比较大小,大则必然会有钻石不能等概率选择左右落法,
小则之前的这么多颗钻石d都是等概率左右分配.
如果至多堆满一边,这d颗钻石每次等概率左右分配, 所有情况有2 ^ d种,对于询问的点,纵坐标反映了它所在边至少要有的钻石数,如果纵坐标是y,
那么至少要y + 1颗钻石, 所以符合要求的情况有C(y + 1, d)+ C(y + 2, d)+....+C(d, d).C(n, m)为组合数, 表示从m中选n个, 这种情况就是从d颗下落钻石中分别选y+1,y+2......d颗落在一边上.
如果满足可以把一条边堆满的情况,我们其实可以把他化为前一种情况,因为d > len + 1了,我们求出d和len+ 1的差记为t,那么我们知道无论怎么下落,两边上都至少有t颗钻石,(抽屉原理思想),又由于钻石是没有区别的,我们不妨把两边都先放上t颗钻石,那么可以知道,剩余的d-2t颗钻石最多填满一条边,化为了前一种情况,只需要注意一下,这时落在某边上的钻石数,从至少y+1颗变成了至少,y+1 - t颗,注意这个值可能是负的,说明,询问的点被我们提前处理时已经放上了钻石,所以特判,p = 1,其他就按原来的组合数求解即可.
最后可以写出如下代码,仅供参考:
#include <stdio.h>#include <math.h>#include<stdlib.h>int com(int n, int m){long long re = 1, i;for (i = 1; i <= n; ++i)re *= (m + 1 - i);for (i--; i > 1; i--)re /= i;return re;}double pp(int x, int y, int n){int len, tem, i;for (len = 1; (len * len + len) / 2 < n; len += 2);if (abs(x) + y > len - 1)return 0.0;else{if (x == 0){if (y){if (n >= (y + 1) * (y + 2) / 2)return 1.0;elsereturn 0.0;}elsereturn 1.0;}else{if (abs(x) + y < len - 1)return 1.0;else{long long sum = 0;tem = n - (len - 2)* (len - 1) / 2;if (tem <= len - 1){for (i = y + 1; i <= tem; ++i)sum += com(i, tem);return (double) sum / (double) (1 << tem);}else{int t = tem - len + 1;if (t > y + 1)return 1.0;else{tem -= 2 * t;for (i = y - t + 1; i <= tem; ++i)sum += com(i, tem);return (double) sum / (double) (1 << tem); }}}}}}int main(){int n, x, y, t, tt = 1;scanf("%d", &t);while (t--){scanf("%d%d%d", &n, &x, &y);printf("Case #%d: %.6lf\n", tt++, pp(x, y, n));}return 0;}
过程中写了一个组合数的函数,计算组合数可能会超过数据类型限制,所以题目中给的n不大.再大一点难度就会增加了,需要另外方法求出组合数,或者换个思路求概率。总之,这题就是这样啦。
- USTCOJ 1388 钻石
- USTCOJ的水题们
- USTCOJ 1365 字符串计数
- USTCOJ 1371 island计数
- USTCOJ 1382 毛毛虫
- USTCOJ 1274 K_Star风波
- USTCOJ 1266 Sequence Again
- USTCOJ 1215 未知星球
- USTCOJ 1264 Longest ‘V’ sequence
- 钻石心
- 人生钻石
- 钻石图形
- 钻石图形
- 钻石(简单)
- 钻石语法
- 钻石布展
- USTCOJ 1281 Unhappy dots 快排模板
- USTCOJ 1359 查找中位数 不用排序
- android mount
- ADO访问数据源——VB与数据库(二)
- android 网络图片双缓存
- Linux下进程通信
- Builder Pattern
- USTCOJ 1388 钻石
- 5名跳水高手参加10米高台跳水决赛,有人让5人根据实力预测比赛结果编程解出比赛结果的实际名次
- 打印出 id=“bj” 该节点的所有子节点的(nodeName, nodeType, nodeValue)
- 基于Eclipse 环境的几个名词
- HTML速成总结
- English notes for Disease
- hdoj_2040 亲和数
- 为什么要使用NodeJS
- 亿能测试培训中心 拟于 6月8日(周六)上午 举行一个 技术讲座(免费)