审题难度大于具体实现难度的一道题。
首先,考虑没有内层约束,就只有x个0、y个1这样的约束的01串,能够取的01子序列个数k。可以发现取值范围即[0, x*y]。
然后注意到从里到外第i个区间[l_i, r_i]内字符串的构造只受第i-1个区间[l_{i-1}, r_{i-1}]的影响,则将第i个区间分成三段,[l_i, l_{i-1}-1], [l_{i-1}, r_{i-1}], {r_{i-1}+1, r_i], 分别称为左、中、右,设最左边区间中0的个数为z,然后对z枚举求k上下界并构造即可。当然你去按照二次函数最大点在不在区间内讨论也可以,但是我没想清楚怎么选取构造就没用这个方法,反正时空限制给的大,这样就够过了。
最后不要忘记在最外层约束外补01。
#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; struct Restriction { int l, r, x, y; long long k; }; class Solution { private: //返回一个01字符串,满足其含有x个0,y个1,k个01子序列(01子序列即一对0、1使得0在1前) string construct_string(int x, int y, long long k) { //0 <= k <= x * y string res_string = ""; if (x == 0) { for (int i = 0; i < y; i++) { res_string += "1"; } return res_string; } /*即从字符串为“x个1 y个0”开始(此时k=0,即"11...100...0"), 先把n1 = k / x(整除)个1移到所有0的右边,再把一个1移到恰好n1 = k % x个0的右边。 结果为res_string = "x - n1 - n3个1, n2个0, n3个1, y - n3个0,n1个1" (n3 = (n2 == 0) ? 0 : 1; 即 n2 == 0 的时候 n3 = 0, 否则 n3 = 1 。) */ int n1 = k / x, n2 = k % x, n3 = (n2 == 0) ? 0 : 1; for (int i = 0; i < y - n1 - n3; i++) { res_string += "1"; } for (int i = 0; i < n2; i++) { res_string += "0"; } for (int i = 0; i < n3; i++) { res_string += "1"; } for (int i = 0; i < x - n2; i++) { res_string += "0"; } for (int i = 0; i < n1; i++) { res_string += "1"; } return res_string; } public: /*主函数,根据约束restrictions生成对应的1个字符串,或当不存在这样的字符串时返回"-1"。 我把restrictions按照约束区间从里到外顺序排列,然后构造也是这样一层层向外构造。 最后不要忘了,如果最外层约束的l和r不是1和n,则需要在前后补上任意的01使长度为n,补全字符串。 (之前忘了这个,一直6/33,非常郁闷-^-!) */ string generate_Zero_One_Substring(int n, vector<Restriction>& restrictions) { string ans_string = ""; if (restrictions.empty()) { for (int i = 0; i < n; i++) { ans_string += "0"; } return ans_string; } auto [l, r, x, y, k] = restrictions[0]; if (k <= (long long) x * y) { ans_string = construct_string(x, y, k); } else{ return "-1"; } int l_next, r_next, x_next, y_next; long long k_next; for (int i = 1; i < restrictions.size(); i++) { Restriction restriction = restrictions[i]; auto [l, r, x, y, k] = restrictions[i - 1]; l_next = restriction.l, r_next = restriction.r, x_next = restriction.x, y_next = restriction.y; k_next = restriction.k; int d1 = l - l_next, d2 = r_next - r, delta_x = x_next - x, delta_y = y_next - y; if (delta_x < 0 || delta_y < 0 || d1 + d2 != delta_x + delta_y) return "-1"; bool existConstruction = false; for (int z = max(0, delta_x - d2); z <= min(d1,delta_x); z++) { //对[l_i, l_{i-1}-1]这一段中的0的个数z进行枚举, //计算第i个区间中给定z对应的k的取值范围 //(在内层第1~i-1个区间内的约束都被满足之后) long long lower_bound = (long long)z * y + z * (d2 - delta_x + z) + x * (d2 - delta_x + z), upper_bound = lower_bound + z * (d1 - z) + (delta_x - z) * (d2 - delta_x + z); if (lower_bound <= k_next - k && upper_bound >= k_next - k) { existConstruction = true; int delta = k_next - k - lower_bound; if (delta < z * (d1 - z)) { ans_string = construct_string(z, d1 - z, delta) + ans_string + construct_string(delta_x - z, d2 - delta_x + z, 0); } else{ ans_string = construct_string(z, d1 - z, z * (d1 - z)) + ans_string + construct_string(delta_x - z, d2 - delta_x + z, delta - z * (d1 - z)); } break; } } //如果枚举后不存在满足约束的构造,返回"-1"。 if (existConstruction == false) return "-1"; } //补全最外层约束以外的字符串 for (int i = 0; i < l_next - 1; i++) { ans_string = "1" + ans_string; } for (int i = r_next; i < n; i++) { ans_string = ans_string + "0"; } return ans_string; } }; int main() { int n, m; cin >> n >> m; vector<Restriction> restrictions(m); int l, r, x, y; long long k; for (int i = 0; i < m; i++) { cin >> l >> r >> x >> y >> k; restrictions[i] = Restriction {l, r, x, y, k}; } sort(restrictions.begin(), restrictions.end(), [] (const Restriction& a, const Restriction& b) { if (a.l != b.l) { return a.l > b.l; } else { return a.r < b.r; } }); Solution solution; cout << solution.generate_Zero_One_Substring(n, restrictions) << endl; return 0; }