posts - 11, comments - 2, trackbacks - 0, articles - 0

Waterloo local contest 1999

Posted on 2009-02-09 18:43 hello_world 阅读(1120) 评论(0)  编辑 收藏 引用
题目
题目分类
 The Trip  分析
 Doublets  字符串,搜索
   
 Factovisors  math
   

The Trip :
题目大意是有群人出去旅行,每个人都付了一定的费用(不等),回来后要把钱均摊,但钱的最小面值是一分(cent),换句话说是个整数,现在问最少需要转移多少钱?
如果转移的钱可以是浮点数(或者保证一定能分得平sample) ,那题目就简单了,但这里稍微烦一些。首先要均摊的话,能做到最大的差价不会超过一分,假设支付费用最小为a, 最大为a+1(我们这里只讨论分不平的情况),而且能算出有x个人要付 a 分, y个人要付 a+1 分,这样就可以开始讨论了
多退少补,而退的钱==补的钱,所以我们只考虑要退多少钱给多付的人
如果有人出的钱 k 大于a+1,那他肯定要退,先让他支付 a+1分。那么这就退了 k - (a+1)分
如果所有大于a + 1分钱的人都考虑了,并且有 q 个人大于或等于 a +1 块钱,就有两种情况
1 q > y,说明 q个人中还有人要退,加上 q - y就好了
2 q <= y,说明多付钱的人当中没人需要退了,结束
只考虑要退多少钱会使思路清晰些

剩下值得一提的是精度问题
有一种比较好的方法可以避免这种问题:
scanf("%d.%d",&tema, &temb);  
直接把钱全部转化为分(cent),这不涉及任何浮点数,所以也不存在精度问题

Doublets
题目意思就是说一个单词与另一个单词如果只有一个字母不同,这两个单词就可以互相到达,给出一些单词作为字典,每次任意询问两个单词的最短路径,并输出!
我的做法,先对字典排序,然后建图,对一个单词,每次构造字典序比它大的且仅相差一个字符的单词,在它后面二分查找是否出现在字典中!这样建图的时间大概是25000*log(25000)*26*16;然后从起点bfs之即可,这一步大概是25000*26*16;不过都是理论上的最坏估计,实际上小得多!
我看了下标程的做法,标程的做法快在建图上,貌似是跟桶排序差不多,每排一次序就扫一遍,在一个桶中的就是能够到达的!

Factovisors

题目大意是给你两个数n, m
问 m 能否整除 n 的阶乘, 即 n!% m ==0  (n, m 都很大 < 2^31  )
可以将 m 质因数分解,对于每一个质数,如果n!中包含的个数 都 比m中的多,说明n!能整除 m 。
1对于m质因数分解只要用o(sqrt(n) );
2对于n!检查一个质因子,用循环除的方法需要log(n),而质数最多不超过log2(m)(假设质因子都挑最小的2,3,5,7。。
这样大部分时间是在分解质因数,算是有效的方法




Waterloo local 1999.06.19

  题目分类
Billiard physics
The Brick Stops Here DP
Election 简单题
   
Boastin' Red Socks 数学方程求最小值,暴力
补充:



Billiard :
题目大意是一张台球桌,假设这桌子没洞,桌子横 a 竖 b ,在桌子中心以某个角度 angel 某个速度 v 弹出一小球,这个小球和横的边界碰撞 p 次,与竖的边界碰撞 q 次,经过 s 秒回到中心(起点)。
已知 a b p q s 求 angel 和 v
我们可以将两个维度分开考虑
水平方向看,碰了 q 次回到原点,显然可以得到走了q*a长度                                            
竖直方向看,同理也可以知道他走了p*b;
那么他就等效于这么一个三角形,o(0, 0),A(q*a,0),B(p*b,q*a),求得角度是<AoB,总路程是oB





The Brick Stops Here:
这是一道典型的DP题目,其实就是背包问题;我们用dp[i][j][k]表示前i种砖中用了j种砖总含铜量为k的最少费用,那么dp[i][j][k]=min{dp[i-1][j-1][[k-copper[i]]+price[i] , dp[i-1][j][k]};对于该题i<=200,j<=20,k<=20*1000!这个时间复杂度可以勉强接受,因为其实可以求出 j  和 k 的上限!而数组也可以省去第一维,避免超内存,其实根据上面的转移方程就可以看出来跟背包的思想很类似,所以可以从后往前倒推!还有就是建议先全都处理出来然后再一起找出答案!核心代码如下:
 1    int i,j,k,h;
 2    for(i=0;i<=UP_N;i++)
 3        for(j=0;j<=UP_W;j++)
 4               dp[i][j] = PINF;
 5    dp[0][0]=0;
 6    for(k=0;k<n;k++)
 7        for(i=UP_N;i>=1;i--)
 8            for(j=UP_W;j>=copper[k];j--)
 9                checkmin(dp[i][j],dp[i-1][j-copper[k]]+price[k]);
10




Boastin' Red Socks

题目大意是有一个健忘的小孩不知道自己有多少只红色的袜子,多少只黑色的袜子(他只有这两种袜子),但他知道从中他拿出两只红色的袜子的概率是 p / q (q=>p>=0   q>0),总共最多有50,000只袜子,让你求满足条件的情况中袜子总数最少的那种中的红袜子的数量
假设有x只红袜子,总共有sum只袜子
p/ q = C(x,2) / C(sum, 2)
由于sum < 50000,对于这么小的一个数,我们可以暴一暴
从小到大枚举 sum,解关于 整数 x 的方程,如果途中得到可行解就可以跳出,它是总数最少的
这个剪枝好像也比较重要,不加会超时
当然这个枚举过程也可以用二分来加速,就更快了
在计算中注意细节,避免溢出




只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理