首页 > 试题广场 >

小红的01子序列构造(hard)

[编程题]小红的01子序列构造(hard)
  • 热度指数:1285 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 512M,其他语言1024M
  • 算法知识视频讲解
\hspace{15pt}小红希望你构造一个长度为 n\tt 01 串,满足 m 个性质:对于 i \in [1, m] ,区间 [l_i, r_i] 有恰好 x_i\tt 0y_i\tt 1k_i\tt 01 子序列
\hspace{15pt}给定的限制区间为两两包含关系。即对于 i \neq j ,若 l_i \leq l_j ,则 r_i \geq r_j ,反之亦然。

\hspace{15pt}子序列为从原字符串中删除任意个(可以为零、可以为全部)字符得到的新字符串。

输入描述:
\hspace{15pt}第一行输入两个正整数 n,m \left(1\leq n,m \leq 10^5\right) 代表 \tt 01 串的长度、限制的数量。
\hspace{15pt}接下来的 m 行,每行输入五个非负整数 l_i,r_i,x_i,y_i,k_i \left(1\leq l_i \leq r_i \leq n;\ 0\leq k_i \leq 10^{10};\ 0\leq x_i,y_i \leq r_i-l_i+1;\ x_i+y_i=r_i-l_i+1\right) ,代表构造的 \tt 01 串需满足区间 [l_i,r_i] 有恰好 x_i\tt 0y_i\tt 1k_i\tt 01 子序列。
\hspace{15pt}保证给定的任意两个区间均为互相包含关系。


输出描述:
\hspace{15pt}如果答案不存在,直接输出 -1 ;否则,在一行上输出一个长度为 n\tt 01 串。

\hspace{15pt}如果存在多个解决方案,您可以输出任意一个,系统会自动判定是否正确。注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。
示例1

输入

4 2
1 4 2 2 4
2 3 1 1 1

输出

0011
示例2

输入

4 2
1 4 2 2 3
2 3 1 1 1

输出

-1
package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"sort"
	"strconv"
	"strings"
)

// 定义区间结构体
type Interval01 struct {
	l, r, x, y, k int
}

// 生成满足条件的字符串
func makeStr(x, k, l int) string {
	y := l - x
	if y == 0 {
		return strings.Repeat("0", l)
	}

	if k%y == 0 {
		return strings.Repeat("0", k/y) + strings.Repeat("1", y) + strings.Repeat("0", x-k/y)
	}

	return strings.Repeat("0", k/y) +
		strings.Repeat("1", y-k%y) +
		"0" +
		strings.Repeat("1", k%y) +
		strings.Repeat("0", x-k/y-1)
}

func main() {
	reader := bufio.NewReader(os.Stdin)

	// 读取输入
	line, _ := reader.ReadString('\n')
	parts := strings.Fields(line)
	length, _ := strconv.Atoi(parts[0])
	num, _ := strconv.Atoi(parts[1])

	// 读取限制条件
	limits := make([]Interval01, num)
	for i := 0; i < num; i++ {
		line, _ = reader.ReadString('\n')
		parts = strings.Fields(line)
		limits[i].l, _ = strconv.Atoi(parts[0])
		limits[i].r, _ = strconv.Atoi(parts[1])
		limits[i].x, _ = strconv.Atoi(parts[2])
		limits[i].y, _ = strconv.Atoi(parts[3])
		limits[i].k, _ = strconv.Atoi(parts[4])
	}

	// 按区间大小排序
	sort.Slice(limits, func(i, j int) bool {
		return (limits[i].r - limits[i].l) < (limits[j].r - limits[j].l)
	})

	// 处理第一个区间
	li, ri, xi, yi, ki := limits[0].l, limits[0].r, limits[0].x, limits[0].y, limits[0].k

	if ki > xi*yi {
		fmt.Println(-1)
		return
	}

	s := makeStr(xi, ki, ri-li+1)

	// 处理剩余区间
	for idx := 1; idx < num; idx++ {
		lj, rj, xj, yj, kj := limits[idx].l, limits[idx].r, limits[idx].x, limits[idx].y, limits[idx].k
		n, m := li-lj, rj-ri

		// 计算xa的范围
		L := getMax(0, xj-xi-m)
		R := getMin(n, xj-xi)
		if L > R {
			fmt.Println(-1)
			return
		}

		// 计算二次不等式系数
		A := xj + yi + n
		B := kj - ki - xj*(m+xi-xj)
		C := 2*xi + m + yi - xj
		D := kj - ki + xi*(xj-xi-m)

		// 检查判别式
		if A*A < 4*B || C*C < -4*D {
			fmt.Println(-1)
			return
		}

		// 解二次不等式
		left1 := (float64(A) - math.Sqrt(float64(A*A-4*B))) / 2
		right1 := (float64(A) + math.Sqrt(float64(A*A-4*B))) / 2
		left2 := (-math.Sqrt(float64(C*C+4*D)) - float64(C)) / 2
		right2 := (math.Sqrt(float64(C*C+4*D)) - float64(C)) / 2

		// 求交集
		left0 := int(math.Ceil(math.Max(left1, left2)))
		right0 := int(math.Floor(math.Min(right1, right2)))

		if left0 > right0 {
			fmt.Println(-1)
			return
		}

		// 求特解
		var xa int
		if left0 < L {
			if right0 >= L {
				xa = L
			} else {
				fmt.Println(-1)
				return
			}
		} else if left0 <= R {
			xa = left0
		} else {
			fmt.Println(-1)
			return
		}

		// 计算ka和kb
		ka := getMin(D-C*xa-xa*xa, xa*(n-xa))
		kb := getMax(0, D-C*xa-n*xa)
		xb := xj - xi - xa

		// 更新字符串
		s = makeStr(xa, ka, n) + s + makeStr(xb, kb, m)
		li, ri, xi, yi, ki = lj, rj, xj, yj, kj
	}

	// 补充前后缀
	if li > 1 {
		s = strings.Repeat("0", li-1) + s
	}
	if ri < length {
		s = s + strings.Repeat("0", length-ri)
	}

	fmt.Println(s)
}

// 辅助函数
func getMax(a, b int) int {
	if a > b {
		return a
	}
	return b
}

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

发表于 2025-04-10 14:29:39 回复(0)