第一行输入两个正整数
代表
串的长度、限制的数量。
接下来的
行,每行输入五个非负整数
,代表构造的
串需满足区间
有恰好
个
,
个
,
个
子序列。
保证给定的任意两个区间均为互相包含关系。
如果答案不存在,直接输出
;否则,在一行上输出一个长度为
的
串。
如果存在多个解决方案,您可以输出任意一个,系统会自动判定是否正确。注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。
4 2 1 4 2 2 4 2 3 1 1 1
0011
4 2 1 4 2 2 3 2 3 1 1 1
-1
package com.haust.hj; import java.util.*; /** 核心关系式: 若两个相邻区间:[a,b](有xa个0,ya个1,ka个01子序列), [b+1,c](有xb个0,yb个1,kb个01子序列) 则合成的新区间:[a,c]有ka+kb+xa*yb个01子序列. 若已知一个区间的0个数和1个数, 则当它左侧全为0, 右侧全为1时, 有最大的01子序列个数, 最大值为0、1个数的乘积,反之为0. 证明: 区间[a,b]中的排序分别为[o1 l1 o2 l2 ...... on ln],其中oi为第i次出现字符连续为0的串,li是为1 o = o1 + o2 + ... +on l = l1 + l2 + ... +ln 则有通式: ka = (o1+o2+......+on)*ln + (o1+o2+......+on-1)*ln-1 + ...... + o1*l1 即 1的长度在0-ln的可能 加上 1的长度在ln-(ln+ln-1)的可能 加上 ...... 加上 1的长度在(l-l1)-l的可能 显然有 ka<=o*l (o1+o2+......+on)*ln + (o1+o2+......+on-1)*ln-1 + ...... + o1*l1<= (o1 + o2 + ... +on)*(l1 + l2 + ... +ln) =(o1 + o2 + ... +on)*ln + (o1 + o2 + ... +on)*(ln-1) + ......+ (o1 + o2 + ... +on)*l1 当且仅当 它左侧全为0, 右侧全为1时, 有最大的01子序列个数, 最大值为0、1个数的乘积,即ka=o*l. 在根据通式: ka = (o1+o2+......+on)*ln + (o1+o2+......+on-1)*ln-1 + ...... + o1*l1 易知区间:[a,c]的 k=ka+kb+xa*yb; 解题: 对于两个大小区间, D1:[li,ri],D2:[lj,rj], 小区间D1包含于大区间D2, 即lj<=li<=ri<=rj. 把大区间分成三份: [lj,li):长度为n=li-lj, 有xa个0、ya个1、ka个01子序列, [li,ri]:长度为l=ri-li+1, 有xi个0、yi个1、ki个01子序列, (ri,rj]:长度为m=rj-ri, 有xb个0、yb个1、kb个01子序列, 则有等式: k = xa*yi + xi*yb + xa*yb + ka + kb + ki 其中,已知: ki, k, xi, yi, 和区间的 li, ri, lj, rj 和等式 xi+xa+xb, lr-li+1 = xa+ya, li-rj+1 =xb+yb 我们只需要枚举xa的个数,就能计算出清楚xb,ya,yb. k = xa*yi + xi*yb + xa*yb + ka + kb + ki 而 0 <= ka + kb <= xa*ya + xb*yb 所以当大区间的k确定时,我们只需要枚举到一个合适的xa,并尽量的把 ka最大,就能算出其中的一个结果。 */ class Par{ int l; int r; int index; public Par (int a , int b, int c){ l = a; r = b; index = c; } @Override public String toString() { return "l:"+l+",r:"+r+",index:"+index; } } public class HJ119 { //给出区间[l , r],零的个数为cnt0,一的个数为r-l+1-cnt0,字串为k的字符串 static void fill(int l, int r, int cnt0, int k, int[] ans) { int cnt1 = r - l + 1 - cnt0; for (int i = l; i <= r; i++) { if (k >= cnt1) k -= cnt1; else { ans[i] = 1; cnt1--; } } } public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int m = in.nextInt(); int[] ans = new int[n+1]; int[] l = new int[m+1]; int[] r = new int[m+1]; int[] a = new int[m+1]; int[] b = new int[m+1]; int[] c = new int[m+1]; ArrayList<Par> list = new ArrayList<>(); for (int i = 1; i <= m; i++) { l[i] = in.nextInt(); r[i] = in.nextInt(); a[i] = in.nextInt(); b[i] = in.nextInt(); c[i] = in.nextInt(); list.add(new Par(l[i],r[i],i)); } Collections.sort(list, new Comparator<Par>() { @Override public int compare(Par o1, Par o2) { if (o1.l > o2.l) return -1; if(o1.l==o2.l) return o1.r - o2.r; return 1; } }); for (int i = 1; i < l.length; i++) { System.out.println(); System.out.println(l[i] + "," + r[i] + "," + a[i] + "," + b[i] + "," + c[i]); System.out.println(list.get(i-1).toString()); } for (int i = 1; i <= m; i++) { int p = list.get(i-1).index; int pre; if(i==1) pre = 0; else pre = list.get(i-2).index; int prel = l[pre]; int prer=r[pre]; int lenl = l[pre]-l[p]; int lenr = r[p]-r[pre]; int basea=a[pre],baseb=b[pre],basec=c[pre]; if(i==1) { lenl = 0; lenr = r[p] - l[p] + 1; basea = baseb = basec = 0; } int cnt0 = a[p] - basea; Boolean flag = false; for (int x = 0; x <= Math.min(cnt0, lenl); x++) { int cnt0l = x, cnt0r = cnt0 - x; int cnt1l = lenl - cnt0l; int cnt1r = lenr - cnt0r; // k - ka -kb int basek = basec + cnt0l * baseb + cnt1r * basea + cnt0l * cnt1r; // ka,ba取最大的值,即xa*ya + xb*yb int addonk = cnt0l * cnt1l + cnt0r * cnt1r; if (cnt1l < 0 || cnt1r < 0) continue; // k = xa*yi + xi*yb + xa*yb + ka + ba + ki 而 0 <= ka+kb <= xa*ya + xb*yb if (c[p] > basek + addonk || c[p] < basek) continue; flag = true; int addon = c[p] - basek; // 尽量的把 ka最大 if (addon <= cnt0l * cnt1l) { fill(l[p], l[p] + lenl - 1, cnt0l, addon, ans); fill(r[p] - lenr + 1, r[p], cnt0r, 0, ans); } else { fill(l[p], l[p] + lenl - 1, cnt0l, cnt0l * cnt1l, ans); fill(r[p] - lenr + 1, r[p], cnt0r, addon - cnt0l * cnt1l, ans); } break; } if(!flag){ System.out.println(-1); return; } } for(int i=1;i<=n;i++) System.out.print(ans[i]); } }
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
}