技巧:
尺取 结果二分
思路
题目意思很坑,卡了半天没搞懂意思。 简单地说T次操作, 将A数组的所有子序列(连续的)每一个第K大的元素插入容器B ,然后再从B中找到第M大的数是多少。
首先 把问题转换(反推导 第M大说明每组子序列里面的K组成的B中, M的大小排行排行就是M, 也就是说有M-1组子序列 K值比M大)
假设B容器中第M大的元素是x。
然后通过尺取法验证假设值是否合理。 即如果满足第k大的子序列数量超过了M 那么说明这个假设X太小,反之X太大,需要正好等于
那怎么找到最合理的呢?
我们不停的将x在可行的范围里不断加大(结果二分尝试). 找到了那个最极限能够满足的seqcnt >= M的就是第M大的数 (其实最后一次就是等于)。
实现
package main import ( "bufio" . "fmt" "io" "os" "strconv" "strings" ) func cvtstrArr(strArr []string) []int { ans := make([]int, len(strArr)) for i := 0; i < len(strArr); i++ { ans[i], _ = strconv.Atoi(strArr[i]) } return ans } // 尺取法 --- 统计在x的情况下,满足第k大的子序列的数量。 func judge(arr []int, x, k, m int) bool { seqcnt := 0 // 满足条件的子序列数量 gtecnt := 0 // 当前大于等于x的个数 j := 0 // 头位置 for i := 0; i < len(arr); i++ { if arr[i] >= x { gtecnt++ } if gtecnt == k { seqcnt += len(arr) - i for arr[j] < x { seqcnt += len(arr) - i j++ } gtecnt-- j++ } } return seqcnt >= m } // https://ac.nowcoder.com/acm/problem/14301 func NC14301(_r io.Reader, _w io.Writer) { in, out := bufio.NewReader(_r), bufio.NewWriter(_w) defer out.Flush() cntStr, _ := in.ReadString('\n') cntStr = strings.TrimSpace(cntStr) cnt, _ := strconv.Atoi(cntStr) for cnt > 0 { firstLine, _ := in.ReadString('\n') firstLine = strings.TrimSpace(firstLine) firstArr := cvtstrArr(strings.Split(firstLine, " ")) secondLine, _ := in.ReadString('\n') if firstArr[0] >= firstArr[1] { secondLine = strings.TrimSpace(secondLine) secondArr := cvtstrArr(strings.Split(secondLine, " ")) l, r := 0, int(^uint(0)>>1) for l <= r { x := l + (r-l)/2 if judge(secondArr, x, firstArr[1], firstArr[2]) { l = x + 1 } else { r = x - 1 } } Fprintln(out, l-1) } cnt-- } } func main() { NC14301(os.Stdin, os.Stdout) }