CF 1743D. Problem with Random Tests(贪心)
D. Problem with Random Tests(贪心)
题意
给出一个01串s,请你任意选择两个子串s1, s2,输出将他们向右对齐按位与的最大值的二进制表示。
思路
首先我们要知道,二进制表示最大,一定是长度越长越好,所以s1一定是选择整个串的。那么我们现在就需要思考s2要从哪里找。因为是向右对齐,所以原串s如果有前导0就没办法变1,所以我们要去除一下前导0。我们可以显而易见地想到,s1(去前导0后)中的第一个0是一定要变成1的,又因为是按右对齐的,所以我们只能从这个0左边的1选择s2的头。这样讲可能很抽象,我们举一个例子。
\(1110011101\)是s1,那么想要把\(s1_4\)变成1,我们的\(s2\)的开头就只能在前3个1里面选,然后\(s2\)越长越好。因为题目说数据均随机生成,我们在遇到第一个0之前一直暴力匹配后取最大值即可(后面已经不可能满足让第一个0变1的可能性了)。
实现
void solve()
{
cin >> n >> s;
string res = s;
int st;
//去前导0
for(int i = 0; i < n; i ++)
if(s[i] == '1')
{
st = i;
break;
}
for(int i = st; i < n; i ++)
{
string tmp = s;
for(int k = st, j = i; k < n && j < n; k ++, j ++)
tmp[j] = max(s[k], s[j]);
res = max(res, tmp);
if(s[i] == '0') //因为贪心,所以第一个0一定是跟他前面的1配对的。
break;
}
//去前导0
reverse(all(res));
while(res.size() > 1 && res.back() == '0') res.pop_back();
reverse(all(res));
cout << res << '\n';
}