湖南大学第十六届程序设计竞赛

  1. https://ac.nowcoder.com/acm/contest/18196/A

大意:给定直角平面坐标系上三个坐标(整数点),判断是直角三角形还是钝角三角形还是锐角三角形,或者构不成三角形。

思路:判断构不成三角形时没想好,导致没做出。实际上在给出三个点,只要三点不共线,就一定能构成三角形。所以判断能不能构成三角形只需要判断是否共线就行了。和给出三条边判断能不能构成三角形是不一样的。对于判断是否共线可以通过向量法判断。x1 * y2 - x2 * y1。判断构成什么三角形,有简单的方法类比于判断是否构成直角三角形。

总结:做题前要认真思考,不要凭感觉。

  1. https://ac.nowcoder.com/acm/contest/18196/D

大意:有n个窗口,m个人,并且小A在最后的位置,即排第m位,每个人去某个窗口的概率在任何时候都是相同的,即概率为 1/n。 如果小A和其他人去了同一个窗口,原先在他前面的还是在他前面,求小A排名的期望值。(1<=n,m<=1e9)

思路:通过找规律猜测最终是做出来了,但是太费事,而且还不是正解。

正解思考方式如下:因为要求排名的期望值,从位置的角度出发,前面有m-1个人,重新排队候在小A前面的人数为 (m-1) * (1/n) 。因为求的是排名,所以结果为 (m-1) * (1/n) +1。

  1. https://ac.nowcoder.com/acm/contest/18196/F

思路:签到,高精度

  1. https://ac.nowcoder.com/acm/contest/18196/I

大意:有两个相同硬度的球,但是不知道具体硬度,先要通过n层高的楼测试,并且到n+1一定会碎。一个球碎了之后就不能再用了。求测出不会碎的最高楼层的最坏情况下的最少次数。(1<=n<=1e18)

思路:如果有无限个球,我们就不用害怕球碎了,可以用二分来做。但是只有两个球怎么办呢?我们可以想想一个球怎么测,只能从下一点点往上测,这样才能保证准确测出最高楼层。我们试着模拟下样例,5层,答案是3。它的测法是这样的,第一次从3开始测,如果碎了,剩一个鸡蛋从测1,2,用了三次,如果没有碎,继续用第一个求继续往上测,在3的时候已经测了一次了,还剩两次,所以在3+2即5的地方测,如果碎了,再测4,总共测了三次。答案是3就是这样来的。知道了这个过程就可以做了。可以二分答案验证,也可以直接做。这里写直接做的做法:假设最少需要测k次,那么第一次在k测,然后在 k+k-1测,再然后在 k+k-1+k-2测…最后是 k+k-1+k-2+…+1也就是等差数列求和。即k * (k+1) / 2 >=n

解 k 就行了。即 k * (k+1) >=n * 2 。怎么解呢? 代码如下:

int ans=sqrt(n*2);
while(ans*(ans+1)<n*2)ans++;
  1. 上题的原题模型 https://www.acwing.com/problem/content/description/1050/

大意:大致和上题一样,只不过没有给出鸡蛋的数目,n层楼,m个鸡蛋,求最坏情况下的测试的最少次数。(1<=n<=100,1<=m<=10)。
此题有两种做法,都是基于dp,时间复杂度不一样。
思路1:
状态表示:f[i,j] 测量区间为 i ,最多用 j 个鸡蛋的方案。属性为最坏方案的最小测量次数。
状态计算:根据某个鸡蛋有没有用过分两大类,用或不用,不用,显然为 f[i,j-1]。用的话又可以根据在哪一层用了该鸡蛋 分为 第1层用, 2 ,…k …i 层用,
对于在第 k 层用 如果碎了则 f[k-1,j-1] 没碎 f[i-k,j].因为是最坏情况,所以是
max(f[k-1,j-1],f[i-k,j])+1。枚举k 求 min
时间复杂度 O( n 2 {n^2} n2m)。
思路2:
状态表示:f[i,j] 表示最多用 j 个鸡蛋,最坏测 i 次 的方案
属性为:测量的最大区间长度。
对于某个鸡蛋测了位置 k, 如果烂了则为 f[i-1,j-1] 没烂为f[i-1,j]
对于该鸡蛋要么烂要么不烂,是确定的。所以两段是独立的,要是f[i,j]最大,两段分别取最大即f[i,j]=f[i-1,j-1]+f[i-1,j]+1.
答案为 使得f[k,m]>=n 最小的 k 。
时间复杂度 O( n 2 {n^2} n2)。

  1. https://ac.nowcoder.com/acm/contest/18196/L

签到 bfs。

分割线:


  1. https://ac.nowcoder.com/acm/contest/18196/B

大意:初始数字是1,现有以下两个操作:操作1:将数字扩大10倍,操作2:将数字加上 x-1 。问最少操作几次可以将数字变成 n 的整数倍。1<=n<=1000000, 1≤x≤1000000000。
思路:这道题很容易看出怎么做,用 bfs。问题在于 数据太大,开不了这么大的内存,但是我们要将数字变成 n 的整倍数,可以全部%n,这样就将问题变成了从 1 到 0 的 bfs 。即 k=k * 10 % n k=(k+x-1) % n 。时间复杂度 O(n)。注意开一个数组d 既用来标记某个点有没有走过,又用来纪录距离,否则会爆内存。还有很重要的一点是特判n=1的情况,结果为0.

总结:有取模操作的时候看能不能先取模,对于模数为1的时候一定要特别注意。

  1. https://ac.nowcoder.com/acm/contest/17905/D

大意:管道取珠游戏,具体具体大意点击链接

思路:对于一道题目尤其是和排列组合有关的题,出题人给的需要求的式子往往是由实际意义的,当我们挖掘出实际意义之后才能更好的下手。对于此题我们知道了操作方式的个数即 C[n+m,n]。即从n+m次推出珠子中选n次推上面的珠子,也等于推完珠子构成的序列个数,这些序列有些是一样的,我们假设有k种不同的序列,第k种序列的个数为a[k]。则有 C[n+m,n]=a[1]+a[2]+…+a[k]。 现在要求 a [ 1 ] 2 a[1]^2 a[1]2+ a [ 2 ] 2 a[2]^2 a[2]2+…+ a [ k ] 2 a[k]^2 a[k]2

即 a[1] * a[1] +a[2] * a[2] +…+ a[k] * a[k]。先来想想它的实际意义是什么?a[1] * a[1] ? 也就是两台一模一样的机器 A,B。 A B两台机器同时推出 第一种序列的个数 。接下来就可以做了。动态规划

状态表示 f[a,b,c,d] 表示 A机器的上管道推出 a 个小球,下管道推出 b 个小球,B机器的上管道推出 c个小球,下管道推出 d 个小球 ,且构成序列一样的的方案。属性为: 数量。

根据最后一步,将f[a,b,c,d]划分为 A上B上,A上B下,A下B上,A下B下。

这时我们发现,每个管道中球个数最多500个,但是f[510,5100,510,510]是开不了的。那怎么办呢?根据状态定义我们发现 a+b和c+d 始终是相等的,所以我们就可以去掉 d 这一维,开三维就够了。具体状态转移方程如下:

f[0][0][0]=1
for(int a=0;a<=n;a++)
        for(int b=0;b<=m;b++)
            for(int c=0;c<=n;c++)
                {
                    int d=a+b-c;
                    if(d<0)continue; //注意 d 得保证 >=0
                    if(a>=1&&c>=1&&s[1][a]==s[1][c])f[a][b][c]+=f[a-1][b][c-1];
                    if(a>=1&&d>=1&&s[1][a]==s[2][d])f[a][b][c]+=f[a-1][b][c];
                    if(b>=1&&c>=1&&s[2][b]==s[1][c])f[a][b][c]+=f[a][b-1][c-1];
                    if(b>=1&&d>=1&&s[2][b]==s[2][d])f[a][b][c]+=f[a][b-1][c];
                    f[a][b][c]%=M;
                }

总结:当我们发现要求的东西是个奇怪的式子,尤其在排列组合类的问题中时,我们要试着去想想它是否有什么实际意义,从实际意义出发。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值