题意

有n个盒子,可以进行m次操作,每次操作有2种

  • 向编号为x的盒子里放一个小球
  • 向除了编号x的其他n-1个盒子里放一个小球

求第几次操作后,所有盒子里至少都有一个小球

思路

答案是具有单调性的,因为每次都是往盒子里放小球,第x次操作后,所有的盒子里至少有一个小球的话,那么第x+1操作后,也肯定满足这个条件。而且这个操作的顺序是不会改变的,可以二分答案的方式做。

对于二分的check函数,实际上就是判断执行了前mid次操作后,每个盒子里球的个数是否都大于0,操作1和操作2都可以看成对区间的操作,所以可以用差分数组来维护盒子里球的个数,最后求和后判断是否所有的盒子球的个数都大于0就可以知道执行前mid操作能否满足题意

时间复杂度nlogn

Go代码

package main

import (
	"fmt"
)

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

	t, x := make([]int, m+1), make([]int, m+1)
	for i := 1; i <= m; i++ {
		fmt.Scan(&t[i], &x[i])
	}
	l, r := 1, m
	check := func(idx int) bool {
		sum := make([]int, n+1)
		for i := 1; i <= idx; i++ {
			if t[i] == 1 {
				sum[x[i]]++
				if x[i] + 1 <= n {
					sum[x[i]+1]--
				}
			} else {
				//[1,x-1] [x+1,n]
				sum[1]++
				sum[x[i]]-- //x[i]-1+1
				if x[i] + 1 <= n {
					sum[x[i]+1]++
				}
				//sum[n+1]--
			}
		}
		for i := 1; i <= n; i++ {
			sum[i] += sum[i-1]
			if sum[i] == 0 {
				return false
			}
		}
		return true
	}
	ans := -1
	for l <= r {
		mid := (l + r + 1) / 2
		if check(mid) {
			//还可以更少
			r = mid - 1
			ans = mid
		} else {
			l = mid + 1
		}
	}
	fmt.Println(ans)
}