描述
题解
一眼看到这个题就感觉见过,或者做过,但是就是想不起来在哪儿做过,然后就陷入了回忆杀……这是一个二幂拆分问题。
赛后找了半天找到个不错的文章,专门讲编译器的这个优化。根据这个文章和一个前辈的代码改写了一个(代码 One)。
这里需要注意的是,求出最少的项数 x 后,最后的结果为 2∗x−1 。
又参考了一下 WerKeyTom_FTD 的代码(代码 Two),感觉稍微好了一丢丢。
说实在的,这个题的确不好想,感觉智商捉急了……
代码
One:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 1e6 + 10;
int n;
char s[MAXN];
int main()
{
scanf("%s", s + 1);
n = (int)strlen(s + 1);
// 头尾的 0 并无影响
int l = 1, r = n;
while (l <= n && s[l] == '0')
{
l++;
}
while (r && s[r] == '0')
{
r--;
}
if (!r)
{
printf("0\n");
return 0;
}
int u = 1, d = 1;
for (int i = r - 1; i >= l; i--)
{
if (s[i] == '1')
{
u = min(u, d) + 1;
}
else
{
d = min(u, d) + 1;
}
}
printf("%d\n", 2 * u - 1);
return 0;
}
Two:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 1e6 + 10;
char s[MAXN];
int sum[MAXN];
int f[MAXN];
int main()
{
scanf("%s", s + 1);
int len = (int)strlen(s + 1);
reverse(s + 1, s + len + 1); // 不倒置也行,不过要反过来搞
for (int i = 1; i <= len; i++)
{
sum[i] = sum[i - 1] + (s[i] == '0');
}
int pos = -1;
for (int i = 1; i <= len; i++)
{
if (s[i] == '0')
{
f[i] = f[i - 1];
}
else
{
f[i] = f[i - 1] + 1;
if (pos)
{
f[i] = min(f[i], f[pos - 1] + 2 + sum[i] - sum[pos - 1]);
}
}
if (pos == -1 || f[pos - 1] + 2 + sum[i + 1] - sum[pos - 1]
>= f[i - 1] + 2 + sum[i + 1] - sum[i - 1])
{
pos = i;
}
}
printf("%d\n", f[len] * 2 - 1);
return 0;
}