https://codeforc.es/gym/102001
L Binary String
签到题,给一个ll范围内的整数K,以及一个二进制串S,求从S中移除尽可能少的字符使得S表示的数不超过K。
思路:贪心+dfs,首先优先移除最高位的1,假如移除这个1之后不会导致前导零出现,这样是最优的。否则,有两种选择,要么从后面移除最高的1或者没有1则随意移除一个0,要么把整个1000...0串移除,把新的1暴露出来,复杂度可能偏高。预处理一个上界,就是不进行移除前导零所得到的答案。有机会根据这个上界进行一定的最优性剪枝。但复杂度仍然玄学。事实上这个预处理出来的就是最优答案,因为删除1肯定比删除0要好,而优先删除高位1肯定更好。上面的两种路线事实上是重复了。一开始的思路就是对的,只是没开longlong溢出了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int ans;
void dfs(ll n,string s,int cnt)
{
if(cnt>=ans)
return;
ll cur=0;
for(int i=0; i<s.length(); ++i)
{
cur=(cur*2ll)+(s[i]-'0');
}
if(cur<=n)
{
ans=cnt;
return;
}
if(s.length()>1&&s[1]=='1')
{
dfs(n,s.substr(1,s.length()),cnt+1);
}
else
{
for(int i=1; i<s.length(); ++i)
{
if(s[i]=='1')
{
string t=s.substr(0,i)+s.substr(i+1,s.length());
dfs(n,t,cnt+1);
t=s.substr(i,s.length());
dfs(n,t,cnt+s.length()-t.length());
return;
}
}
dfs(n,s.substr(0,s.length()-1),cnt+1);
return;
}
}
int main()
{
#ifdef local
freopen("lyz.in","r",stdin);
#endif // local
ll n;
while(cin>>n)
{
string s;
cin>>s;
string cs=s;
ll cur=0;
for(int i=0; i<s.length(); ++i)
{
cur=(cur*2ll)+(s[i]-'0');
}
int cnt=0;
while(cur>n)
{
if(s.length()>1&&s[1]=='1')
{
++cnt;
s=s.substr(1,s.length());
}
else
{
bool suc=0;
for(int i=1; i<s.length(); ++i)
{
if(s[i]=='1')
{
++cnt;
string t=s.substr(0,i)+s.substr(i+1,s.length());
s=t;
suc=1;
break;
}
}
if(!suc)
{
++cnt;
s=s.substr(0,s.length()-1);
}
}
cur=0;
for(int i=0; i<s.length(); ++i)
{
cur=(cur*2ll)+(s[i]-'0');
}
//cout<<s<<endl;
}
ans=cnt;
dfs(n,cs,0);
printf("%d
",ans);
}
}
A. Edit Distance
给一个二进制串S,求一个等长的二进制串T,使得S变为T至少要超过len(S)/2步。每步可以是增删改一个位置。
首先0和1数量不等可以随便构造。等长的情况为什么要这样构造当时没有想清楚,但是感觉这样是对的。首先把开头元素反向,后面接一串反向串。比如原串是1开头的,就搞0111...1,原串是0开头的就搞1000...0,为什么会这样呢?
首先原串串长必为偶数,设为2l,原串是1???...?,我构造0111...1,那么这个1必定要改成0或者删掉,花费至少为1。因为原串的1和0数量相等,所以原串后面有l个0,他们都要变成1,所以至少花费l+1步。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char s[300000];
int main()
{
#ifdef local
freopen("lyz.in","r",stdin);
#endif // Yinku
int T,n=0;
while(~scanf("%s",s+1))
{
n=strlen(s+1);
int o=0,y=0;
for (int i=1; i<=n; i++)
{
if (s[i]=='1')
y++;
else
o++;
}
if (y==1 && o==1)
if (s[1]=='1')
{
printf("01
");
continue;
}
else
{
printf("10
");
continue;
};
if (y>o)
{
for (int i=1; i<=n; i++)
printf("0");
printf("
");
}
else if (y<o)
{
for (int i=1; i<=n; i++)
printf("1");
printf("
");
}
else if (y==o)
{
if (s[1]=='1')
{
printf("0");
for (int i=1; i<=n-1; i++)
printf("1");
printf("
");
}
else
{
printf("1");
for (int i=1; i<=n-1; i++)
printf("0");
printf("
");
}
}
}
}