contest-252

151 阅读3分钟

1.三除数 (略)

2.你可以工作的最大周数 (贪心)

一开始考虑的是双指针模拟,每次用选最大的和最小的相减,然后结果加上最小的两倍,可惜没过,主要是在于从小的还是大的开始,之后一直要维护这个关系,没写出来。 正确的做法应该是从宏观的角度开始分析,首先考虑,如果最大的一个项目比其他所有项目加起来都要大那答案就是其他所有的项目之和+1。反之,则需要进行更进一步的分析:例如,[1,2,3,5],最大的项目任务数为5,因此我们先得到项目4的5个任务的序列5 5 5 5 5,我们依次将其它任务插入以保证相邻不重复,依次得到 5 3 5 3 5 3 5 5,不够,再将2插入,得到5 3 5 3 5 3 5 2 5,此时我们已经能保证5的任务不相邻了。而且我们发现,随着插入的任务数越多,可供后面任务插入的空位越多(大于最大项目的任务数),因此后面的任务只要插入前面序列两个不相邻的任务中间,就不会重复。综上,我们只需要保证任务数最多的项目不重复即可保证所有项目的任务不重复,所以答案就是所有任务之和。

func numberOfWeeks(milestones []int) int64 {
   m := milestones[0]
   sum := milestones[0]
   for i := 1 ; i < len(milestones) ; i++ {
      if milestones[i] > m {
         m = milestones[i]
      }
      sum += milestones[i]
   }
   remain := sum - m
   if m > remain + 1 {
      return int64(remain * 2 + 1)
   }
   return int64(m + remain)
}

3.收集足够苹果的最小花园周长 (数学)

这题主要需要数学推导,比赛的时候推出了递推公式,然后迭代过了,后面看了大佬的答案,他们是给出了通项公式,同时由于题目告诉了范围,所以就能使用二分快速搜索答案。(贴一个渣渣递推版)

func minimumPerimeter(neededApples int64) int64 {
   cur := 2
   var sum int64 = 12
   var pre int64 = 12
   for {
      if sum >= neededApples {
         return int64(cur * 4)
      }
      pre = int64(cur + 2) * 4 + pre + int64(cur * 4) + int64(cur + 1) * 4
      sum += pre
      cur += 2
   }
   return 0
}

4.统计特殊子序列的数目 (dp)

看到子序列优先考虑dp来做,dp0[i]表示由N个0组成的子序列的个数,dp1[i]表示由N个0接着N个1组成的子序列的个数,dp2[i]表示特殊序列的个数。当num[i] == 0时,dp0[i]等于什么呢?首先选这个0可以直接放到dp0[i - 1]个子序列的后面,或者这个0单独成为一个子序列;不选这个0那就是dp0[i - 1],所以dp0[i] = 2dp0[i - 1] * 2 + 1。当num[i] == 1时选这个1,可以把他放到dp0[i - 1]的后面或者dp1[i - i]的后面,不选那就是dp1[i - i],所以dp1[i] = 2 * dp1[i - 1] * dp0[i - 1],dp2[i]同理,不做分析了。由于当前状态之跟上一个状态有关,所以写代码时可以压缩。

func countSpecialSubsequences(nums []int) int {
   mod := 1000000007
   a, b, c := 0, 0, 0
   for i := 0 ; i < len(nums) ; i++ {
      if nums[i] == 0 {
         a = (a * 2 % mod) + 1 % mod
      } else if nums[i] == 1 {
         b = (b * 2 % mod + a) % mod
      } else {
         c = (c * 2 % mod + b) % mod
      }
   }
   return c
}