D. Problem with Random Tests
题意:给定一个长度为
n
n
n 的01串,从中选出两个子串
a
a
a,
b
b
b,记 f(s) 为以s为二进制表示下的十进制数。求 f(a) 0R f(b) 的最大值(输出为不带前导0的01串)。
思路:不难想到两个子串中的一个串必定要选择原串(保留最多的1),然后考虑另一个串怎么取,我们当然希望另一个串最好要尽量使得原串高位的0可以通过异或变为1。本题关键信息:生成数据随机,每个位置是0或1的概率分别是1/2,故一块长度是20的全为1的连续块的概率是1e-6,长度更长概率更低,故可以认为全1连续块不会很长(一开始看到“数据随机生成”,不知道有什么用,现在学会啦!!!套路)。记串的第一块全1连续块的第一个1的位置是i,第一块全1连续块的最后一个位置是j(那么第j+1的位置是0),遍历k=i+1~j+1,将第一个全1连续块的第一个1(第i位置)挪到第k位置(保证第j+1位的0(第一块全1连续块后的第一个0)通过或运算后是1(贪心 尽量让高位为1))。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n;
string s;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>s;
int i;
for(i=0;i<n;++i) if(s[i]=='1') break;
if(i==n) { //全0
cout<<0<<'\n';
}else{
int j=i;
while(j<n-1 && s[j+1]=='1') j++;
string ans=s;
for(int k=i+1;k<=j+1;++k){
string str="";
for(int kk=0;kk<k;++kk) str+='0';
for(int kk=i;kk<n-(k-i);++kk) str+=s[kk];
string str1="";
for(int kk=0;kk<n;++kk){
if(s[kk]=='1' || str[kk]=='1') str1+='1';
else str1+='0';
}
if(str1>ans) ans=str1;
}
bool ok=false;
for(int i=0;i<n;++i){
if(ans[i]=='1'){
cout<<1;
ok=true;
}else if(ok) cout<<0;
}
if(!ok) cout<<0;
cout<<'\n';
}
}