contestDouble-60

169 阅读1分钟

1.找到数组的中间位置(前缀和)

题目数据量很小,无脑暴力也能过。

func findMiddleIndex(nums []int) int {
   pre := make([]int, len(nums))
   pre[0] = nums[0]
   for i := 1 ; i < len(nums) ; i++ {
      pre[i] = pre[i - 1] + nums[i]
   }
   n := len(pre)
   if pre[n - 1] - pre[0] == 0 {
      return 0
   }
   for i := 1 ; i < len(pre) - 1 ; i++ {
      if pre[n - 1] - pre[i] == pre[i - 1] {
         return i
      }
   }
   if pre[n - 2] == 0 {
      return n - 1
   }
   return -1
}

2.找到所有的农场组 (dfs/bfs)

本质就是搜索手速题,需要把起点和终点存一下

func findFarmland(land [][]int) [][]int {
   n := len(land)
   m := len(land[0])
   visited := make([][]bool, n)
   for i := 0 ; i < len(visited) ; i++ {
      visited[i] = make([]bool, m)
   }
   res := make([][]int, 0)
   for i := 0 ; i < n ; i++ {
      for j := 0 ; j < m ; j++ {
         if !visited[i][j] && land[i][j] == 1 {
            t := make([]int, 0)
            t = append(t, i)
            t = append(t, j)
            getLand(visited, land, i, j, n, m, &t)
            res = append(res, t)
         }
      }
   }
   return res
}

func getLand(visited [][]bool, land [][]int, x, y, n, m int, cur *[]int)  {
   if x < 0 || x >= n || y < 0 || y >= m || visited[x][y] || land[x][y] == 0 {
      return
   }
   visited[x][y] = true
   if (x == n - 1 && y == m - 1) || (x + 1 < n && land[x + 1][y] == 0 && y + 1 < m && land[x][y+ 1] == 0) ||
      (x == n - 1 && y + 1 < m && land[x][y+ 1] == 0) || (y == m - 1 && x + 1 < n && land[x + 1][y] == 0) {
      *cur = append(*cur, x, y)
   }
   getLand(visited, land, x, y + 1, n, m, cur)
   getLand(visited, land, x - 1, y, n, m, cur)
   getLand(visited, land, x + 1, y, n, m, cur)
   getLand(visited, land, x, y - 1, n, m, cur)
}

3.树上的操作(模拟)

没搞过竞赛,不知道那些烧操作,就老老实实模拟吧,思路不难都能想到。

type LockingTree struct {
   m map[int]*node
}

type node struct {
   val int
   parent *node
   children []*node
   locked int
   user   int
}

func Constructor(parent []int) LockingTree {
   n := len(parent)
   all := make([]*node, n)
   m := make(map[int]*node)
   for i := 0 ; i < n ; i++ {
      all[i] = &node{
         val:      i,
         parent:   nil,
         children: make([]*node, 0),
         locked: -1,
         user:   -1,
      }
      m[i] = all[i]
   }
   for i := 1 ; i < n ; i++ {
      all[parent[i]].children = append(all[parent[i]].children, all[i])
      all[i].parent = all[parent[i]]
   }
   l := LockingTree{
      m: m,
   }
   return l
}

func (this *LockingTree) Lock(num int, user int) bool {
   if this.m[num].locked == -1 {
      this.m[num].locked = 1
      this.m[num].user = user
      return true
   }
   return false
}

func (this *LockingTree) Unlock(num int, user int) bool {
   if this.m[num].locked == 1 && this.m[num].user == user {
      this.m[num].locked = -1
      this.m[num].user = -1
      return true
   }
   return false
}


func (this *LockingTree) Upgrade(num int, user int) bool {
   // 当前节点没有上锁
   // 没有任何上锁的祖先节点
   cur := this.m[num]
   for cur != nil {
      if cur.locked == 1 {
         return false
      }
      cur = cur.parent
   }
   hasLock := false
   q := make([]*node, 0)
   q = append(q, this.m[num])
   needLock := make([]*node, 0)
   for len(q) > 0 {
      head := q[0]
      q = q[1:]
      if head.locked == 1 {
         hasLock = true
         needLock = append(needLock, head)
      }
      for i := 0 ; i < len(head.children) ; i++ {
         q = append(q, head.children[i])
      }
   }
   if !hasLock {
      return false
   }
   this.Lock(num, user)
   for i := 0 ; i < len(needLock) ; i++ {
      this.Unlock(needLock[i].val, needLock[i].user)
   }
   return true
}

4.好子集的数目 (状压dp+快速幂)

好气,思路就差一点点,还是做得太少了...首先最重要的是1<=num[i]<=30,所以30以内的质数就10个,选或不选一共就1024个状态,所以考虑状压dp,2,3,5,7,11...29这里针对一个num[i]而已,例如6=23,则说明6对应的状态为000...0011=3.所以首先算一下1-30对应的状态,特别的例如4=22其本身就重复,则不参与讨论。接着统计1-30每个数出现了多少次记作num[i],遍历这30个数的状态,针对其中一个状态,需要与所有1024个状态相&,如果答案为0,则可以合并。某个状态j的子集数记作sub[j],当前数字i的状态k的子集数为num[i], sub[j + k] = (sub[j + k] + sub[j] * num[i] % mod) % mod,简单解释一下就是j状态的子集数为sub[j],当前的k&j=0,所以这两个集合可以合并,多出来的个数为sub[j]*num[i]。此外,1作为一个特殊的数字,需要进行单独讨论。显然,只包含1的子集可以添加到满足条件的任何一个子集中去,所以求出只包含1的子集的个数s(选1或者不选1一个2^(1的个数)),最后遍历所有的状态,求出所有满足条件的子集与s相乘就是最终答案。(大佬代码搬运工)

const mod int = 1e9 + 7

func numberOfGoodSubsets(nums []int) int {
   num := make([]int, 31)
   for i := 0 ; i < len(nums) ; i++ {
      num[nums[i]]++
   }
   // 每一种状态下有多少个好子集
   sub := make([]int, 1024)
   // 1-30之间最多只有10个质数 考虑状态压缩表示
   // 2 表示为00...001
   // 首先将1-30质因数分解,比如6=2*3那6的状态就表示为00...0011=3
   // 各个数字的状态4=2*2本身就重复所以直接为0
   good := []int{0, 0, 1, 2, 0, 4, 3, 8, 0, 0, 5, 16, 0, 32, 9, 6, 0, 64, 0, 128, 0, 10, 17, 256, 0, 0, 33, 0, 0, 512, 7}
   for i := 2 ; i <= 30 ; i++ {
      if good[i] > 0 && num[i] > 0 {
         // 当前数字的状态
         k := good[i]
         for j := 1023 ; j >= 0 ; j-- {
            // 不重复的质数
            if sub[j] > 0 && j & k == 0 {
               sub[j + k] = (sub[j + k] + sub[j] * num[i] % mod) % mod
            }
         }
         sub[k] += num[i]
      }
   }
   res := 0
   for i := 0 ; i < len(sub) ; i++ {
      res = (res + sub[i]) % mod
   }
   return pow(2, num[1]) * res % mod
}


func pow(x int, n int) int {
   if n == 0 {
      return 1
   }
   if n == 1 {
      return x
   }
   tem := pow(x, n >> 1)
   res := tem * tem % mod
   if n % 2 == 0 {
      return res
   } else {
      return res * x % mod
   }
}