审题难度大于具体实现难度的一道题。
首先,考虑没有内层约束,就只有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;
}



京公网安备 11010502036488号