https://hihocoder.com/problemset/problem/1527
时间限制:20000ms
单点时限:1000ms
内存限制:256MB
- 样例输入
-
1111
- 样例输出
-
3
描述
在写代码时,我们经常要用到类似 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 最少需要多少单位的时间。
输入
一个01串,表示 a 的二进制形式,从左到右分别是从高位到低位。
0 < 01串的长度之和 ≤ 106。
a > 0。
输出
输出一个数,表示最小需要多少单位的时间可以实现 x × a。
错解:
贪心选择超过两个连续的1的决策不如使用高位减低位的方法,110不如1<<3 – 1<<1
然后,单个1选择直接加上。
如果两个大块(2个连续1以上)中间之隔为1个0,那么可以合并,110110不如 1<<6 – 1<<4 + 1<<3 – 1<<1 = 1<<6 – 1 <<3 – 1<<1
#include <stdio.h> #include <iostream> #include <string.h> #include <stdlib.h> #include <vector> #include <algorithm> #include <queue> #include <map> #include <string> #include <math.h> using namespace std; typedef pair<int,int> P; typedef long long LL; const int INF = 0x3f3f3f3f; const double PI = acos(-1.0); const double eps = 1e-9; const int N = 1e6 + 5; char s[N]; int main() { while(scanf("%s", s) != EOF) { int n = strlen(s); int cnt = 0; int i = 0; while(i < n) { int k = 0; while(i < n && s[i] == ‘1‘) { k++; i++; } if(k == 1) cnt++; else if(k >= 2) cnt += 2; if(k >= 2 && i+2 < n && s[i+1] == ‘1‘ && s[i+2] == ‘1‘) cnt -= 1; if(i < n && s[i] == ‘0‘) i++; } printf("%d\n", 2*cnt-1); } return 0; }
-
题解:很多都是二幂划分的解释,也可以用dp来做
-
从低位往高位考虑。dp[i]表示第i位的时候需要进行最少操作数
-
如果当前位是0,dp[i] = dp[i-1]
-
如果当前位是1,可以有两种选择,直接加上dp[i] = dp[i-1] + 1;
-
或者,把某一部分的0全部补上,然后用高位1减去,例如01100 = 10000 – 00100,也就是 [x, i]全部都变成1,也就是要补上x~i的0
-
dp[i] =min{ dp[x-1] + 2 + sum[i] – sum[x-1]}
-
#include <stdio.h> #include <iostream> #include <string.h> #include <stdlib.h> #include <vector> #include <algorithm> #include <queue> #include <map> #include <string> #include <math.h> using namespace std; typedef pair<int,int> P; typedef long long LL; const int INF = 0x3f3f3f3f; const double PI = acos(-1.0); const double eps = 1e-9; const int N = 1e6 + 5; char s[N]; int sum[N], dp[N]; int main() { scanf("%s", s+1); int n = strlen(s+1); memset(dp,0,sizeof(dp)); memset(sum, 0, sizeof(sum)); reverse(s+1,s+1+n); for(int i = 1; i <= n; i++) sum[i] =sum[i-1] + (s[i] == ‘0‘); dp[0] = 0; int mx = -1; for(int i = 1; i <= n; i++) { if(s[i] == ‘0‘) dp[i] = dp[i-1]; else { dp[i] = dp[i-1] + 1; if(mx > 0) dp[i] = min(dp[i], dp[mx-1] + 2 + sum[i] - sum[mx-1]); } if(mx == -1 || dp[i-1] + 2 + sum[i+1] - sum[i-1] <= dp[mx-1] + 2 + sum[i+1] - sum[mx-1]) mx = i; } printf("%d\n", 2*dp[n]-1); return 0; }
时间: 2024-10-27 02:46:50