可恶的小美

544 阅读3分钟

第一题:小美玩排列

小美拿到了一个排列。她想知道在这个排列中,x和y是否是相邻的。你能帮帮她吗?排列是指一个长度为n的数组,其中 1 到n 每个元素恰好出现一次。

输入描述

第一行输入一个正整数n,代表排列的长度。

第二行输入n个正整数ai,代表排列的元素。

第三行输入两个正整数x和y,用空格隔开。

1 <= n <= 200000

1 <= ai, x,y <= n

保证 x != y

输出描述

如果x和y在排列中相邻,则输出"Yes"。否则输出"No"。

func neighbor(length int, nums []int, x, y int) bool {
   for i := 0; i < length-1; i++ {
      if nums[i] == x {
         if nums[i+1] == y {
            return true
         }
      }
      if nums[i] == y {
         if nums[i+1] == x {
            return true
         }
      }
   }
   return false
}

func main() {
   var length int
   fmt.Scan(&length)

   nums := make([]int, length)
   for i := range nums {
      fmt.Scan(&nums[i])
   }

   var x, y int
   fmt.Scan(&x, &y)
   fmt.Println(neighbor(length, nums, x, y))
}

第二题:小美走公路

有一个环形的公路,上面共有n站,现在给定了顺时针第i站到第i+1站之间的距离(特殊的,也给出了第n站到第1站的距离)。小美想沿着公路第x站走到第y站,她想知道最短的距离是多少?

输入描述

第一行输入一个正整数n,代表站的数量。第二行输入n个正整数ai,前n-1个数代表顺时针沿着公路走,i站到第i+1站之间的距离;最后一个正整数代表顺时针沿着公路走,第n站到第1站的距离。· 第三行输入两个正整数x和y,代表小美的出发地和目的地。

1 <= n <= 10^5

1 <= ai <= 10^9

1 <= x,y <= n

输出描述

一个正整数,代表小美走的最短距离。

func long(nums []int, x, y int) int {
   if x == y {
      return 0
   }

   if x > y {
      x, y = y, x
   }

   var sum int
   for _, i := range nums {
      sum += i
   }

   var res int
   for i := x; i < y; i++ {
      res += nums[i]
   }
   return min(res, sum-res)
}

func min(a, b int) int {
   if a > b {
      return b
   }
   return a
}

func main() {
   var length int
   fmt.Scan(&length)

   nums := make([]int, length)
   for i := range nums {
      fmt.Scan(&nums[i])
   }

   var x, y int
   fmt.Scan(&x, &y)
   x--
   y--
   fmt.Println(long(nums, x, y))
}

第三题:小美切蛋糕

小美有一个矩形的蛋糕,共分成了n行m列,共n*m个区域,每个区域是一个小正方形,已知蛋糕每个区域都有一个美味度。她想切一刀把蛋糕切成两部分,自己吃一部分,小团吃另一部分。

小美希望两个人吃的部分的美味度之和尽可能接近,请你输出 |s1-s2|的最小值。(其中s1代表小美吃的美味度,s2代表小团吃的美味度)

请务必保证,切下来的区域都是完整的,即不能把某个小正方形切成两个小区域。

输入描述

第一行输出两个正整数n和m,代表蛋糕区域的行数和列数。

接下来的n行,每行输入m个正整数,用来表示每个区域的美味度。

1 <=n,m <=10^3

m个正整数均小于10^4

package main

import (
   "fmt"
)

func cake(nums [][]int, x, y int) int {
   xs := make([]int, x)
   ys := make([]int, y)
   sum := 0
   now := 0
   for i := 0; i < x; i++ {
      for j := 0; j < y; j++ {
         xs[i] += nums[i][j]
         ys[j] += nums[i][j]
         sum += nums[i][j]
      }
   }
   res := sum
   for i := 0; i < x; i++ {
      now += xs[i]
      res = min(abs(sum-now-now), res)
   }
   now = 0
   for j := 0; j < y; j++ {
      now += ys[j]
      res = min(abs(sum-now-now), res)
   }
   return res
}

func abs(a int) int {
   if a > 0 {
      return a
   }
   return -a
}

func min(a, b int) int {
   if a > b {
      return b
   }
   return a
}

func main() {
   var x, y int
   fmt.Scan(&x, &y)

   cakeSum := make([][]int, x)
   for i := range cakeSum {
      cakeSum[i] = make([]int, y)
   }
   for i := range cakeSum {
      for j := range cakeSum[i] {
         fmt.Scan(&cakeSum[i][j])
      }
   }
   fmt.Println(cake(cakeSum, x, y))
}

第四题:小美将字符串平铺成矩阵

小美拿到了一个长度为n的字符串,她希望将字符串从左到右平铺成一个矩阵(先平铺第一行,然后是第二行,以此类推,矩阵有x行y列,必须保证x*y=n,即每y个字符换行,共x行)。

该矩阵的权值定义为这个矩阵的连通块数量。小美希望最终矩阵的权值尽可能小,你能帮小美求出这个最小权值吗?

注:我们定义,上下左右四个方向相邻的相同字符是连通的。

输入描述

第一行输入一个正整数n,代表字符串的长度。

第二行输入一个长度为n的、仅由小写字母组成的字符串。

1<=n<=10^4

输出描述

输出一个整数表示最小权值。

package main

import "fmt"

var move = [][]int{{1, 0}, {0, 1}, {-1, 0}, {0, -1}}

func cal(v []string) int {
   n := len(v)
   m := len(v[0])

   vis := make([][]bool, n)
   for i := range vis {
      vis[i] = make([]bool, m)
   }

   var dfs func(x, y int, c byte)

   dfs = func(x, y int, c byte) {
      if x < 0 || x >= n || y < 0 || y >= m || vis[x][y] || v[x][y] != c {
         return
      }

      vis[x][y] = true
      for _, mv := range move {
         dfs(x+mv[0], y+mv[1], c)
      }
   }

   ret := 0
   for i := 0; i < n; i++ {
      for j := 0; j < m; j++ {
         if vis[i][j] {
            continue
         }
         ret++
         dfs(i, j, v[i][j])
      }
   }
   return ret
}

func main() {
   var n int
   fmt.Scan(&n)

   var s string
   fmt.Scan(&s)

   ans := n
   for i := 1; i <= n; i++ {
      if n%i != 0 {
         continue
      }

      v := make([]string, i)
      length := n / i
      for j := 0; j < i; j++ {
         v[j] = s[j*length : (j+1)*length]
      }

      ans = min(ans, cal(v))
   }

   fmt.Println(ans)
}

func min(a, b int) int {
   if a < b {
      return a
   }
   return b
}

第五题:小美染色

美拿到了一棵树,每个节点有一个权值。初始每个节点都是白色。

小美有若干次操作,每次操作可以选择两个相邻的节点,如果它们都是白色且权值的乘积是完全平方数,小美就可以把这两个节点同时染红。

小美想知道,自己最多可以染红多少个节点?

输入描述

第一行输入一个正整数n,代表节点的数量。第二行输入n个正整数ai,代表每个节点的权值。接下来的n-1行,每行输入两个正整数u,v,代表节点u和节点v有一条边连接。

1 <= n <= 10^5

1 <= ai <= 10^9

1 <= u, v <= n

输出描述

输出一个整数,表示最多可以染红的节点数量。

package main

import (
   "fmt"
   "math"
)

const MAXN = 100000 + 5

var g [MAXN][]int
var a [MAXN]int64
var dp0 [MAXN]int64
var dp1 [MAXN]int64

func square(x int64) int64 {
   return x * x
}

func check(x int64) bool {
   t := math.Sqrt(float64(x))
   return square(int64(t)) == x || square(int64(t)-1) == x || square(int64(t)+1) == x
}

func dfs(u, p int) {
   dp0[u] = 0
   dp1[u] = 0

   for _, v := range g[u] {
      if v == p {
         continue
      }

      dfs(v, u)

      dp0[u] += max(dp0[v], dp1[v])

      if check(a[u] * a[v]) {
         dp1[u] = max(dp1[u], dp0[u]-max(dp0[v], dp1[v])+dp0[v]+2)
      }
   }
}

func max(a, b int64) int64 {
   if a > b {
      return a
   }
   return b
}

func main() {
   var n int
   fmt.Scan(&n)

   for i := 0; i < n; i++ {
      fmt.Scan(&a[i])
   }

   for i := 1; i < n; i++ {
      var u, v int
      fmt.Scan(&u, &v)
      u--
      v--
      g[u] = append(g[u], v)
      g[v] = append(g[v], u)
   }

   dfs(0, -1)

   fmt.Println(max(dp0[0], dp1[0]))
}