[hihocoder1527]快速乘法

题目描述

在写代码时,我们经常要用到类似 x × a 这样的语句( a 是常数)。众所周知,计算机进行乘法运算是非常慢的,所以我们需要用一些加法、减法和左移的组合来实现乘一个常数这个操作。具体来讲, 我们要把 x × a 替换成: (x<<a0)op1(x<<a1)op2(x<<a2)...opn(x<<an) 这样的形式,其中opi 是+或者-。

举个例子:x × 15 = (x<<4) - (x<<0)。

在本题中,假设左移(包括左移0)和加法、减法所需要的时间都是一个单位的时间,上述的例子所需要的时间是3。

现在给定常数 a 的二进制形式,求实现 x × a 最少需要多少单位的时间。

dp

题意就是让你用一堆二的次幂的加减凑出a,要求拿了凑的数个数尽量小。
我们考虑设f[i]表示凑出了a的前i位的最小操作数。
如果第i位是0,有f[i]=f[i-1]。
如果第i位是1,有两种操作:
直接加上这位,f[i]=f[i-1]+1。
或者加上 2i+1 ,然后减去一个 2j ,这样[j,i]全部都是1,多出来的部分减掉。
f[i]=min(f[j-1]+2+sum[i]-sum[j-1])
枚举j则复杂度是平方。
注意不同的两个决策j和k,在i移一单位时,变化量一样,因此最优决策很容易维护。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=1000000+10;
char s[maxn];
int sum[maxn],f[maxn];
int i,j,k,l,t,n,m,ans,mx;
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    reverse(s+1,s+n+1);
    fo(i,1,n) sum[i]=sum[i-1]+(s[i]=='0');
    mx=-1;
    fo(i,1,n){
        if (s[i]=='0') f[i]=f[i-1];
        else{
            f[i]=f[i-1]+1;
            if (mx) f[i]=min(f[i],f[mx-1]+2+sum[i]-sum[mx-1]);
        }
        if (mx==-1||f[mx-1]+2+sum[i+1]-sum[mx-1]>=f[i-1]+2+sum[i+1]-sum[i-1]) mx=i;
    }
    ans=f[n];
    printf("%d\n",ans*2-1);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值