SillyDarkGK has two type of numbers:
type1. 2^x. (2, 4, 8, 16, …)
type2. -(2^x). (-2, -4, -8, -16, …)
He wants a new number S, for getting S, he should choose some numbers that the sum of them is S.
For example, if SillyDarkGK wants 5, he can use 2, 2, -1, -1, -1, 8 and -4 to get it. (He can use number arbitrary times.)
(S is very big, so we will give you a 01-string to describe it.)
Choosing is boring, so SillyDarkGK wants to choose numbers as fewer as possible. To increase the difficulty, SillyDarkGK can’t use some special numbers.
(We will also give you two 01-string to describe what you can’t use.)
it’s guaranted that there is at least one way to solve it and answer won’t exceed
1e9.
Input
Multiple query.
On the first line, there is a positive integer T, which describe the number of data. Next there are T groups of data.
for each group, the first line have a positive integer n which describe the number of bits of S.
and on the second line there is an n-length-01-string to describe S, from low to high. On the third line there is an n-length-01-string which describe the type1 number that you can’t use, from low to high, if there is a ’1’ on the x-th digit, you can’t use two
to the power of x.
On the last line there is an n-length-01-string which describe the type2 number that you can’t use, from low to high, if there is a ’1’ on the x-th digit, you can’t use minus two to the power of x.
There is a blank line before each groups of data.
T<=1000, n<=100000, sum of n<=1000000, answer won’t exceed 1e9
Output
Your output should include T lines, for each line, output the answer for the corre- sponding datum.
Sample Input
3 6 110010 110101 011111 9 100101110 011111111 111111111 5 11111 00000 00000
Sample Output
3 233 2
Hint
for the first datum, SillyDarkGK will use 4, 16 and -1; for the second datum, SillyDarkGK will use 1 for 233 times; for the third datum, SillyDarkGK will use 32 and -1.
思路:考虑按位递推dp,对于每位上的数,要么加上2^i,要么减去2^i,要么不进行操作。
dp[i][0]表示前i位,且第i位采用+操作,dp[i][1]表示采用-操作
如果s 的i位是0,代表这位其实不要填充,所以可以考虑两种选择,不进行任何操作或者考虑去加(考虑去加是因为可能前面采用了减,需要加去多余的)。
如果s的i为是1,代表这位需要填充,所以考虑加上这步的代价。
对于减的操作,需要处理一个s的取反窜,并且要加上1,加上1的目的是因为只有保证这个数不是0,我们才能减(如111111,取反后是000000,如果不加1的话,是无法考虑去减的)
还有就是根据串的限制条件来计算最小代价,最小代价一定是:如果这个位置能取,那么它为1,如果不能取,一定是它前一个的两倍。
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
#include <stack>
typedef long long ll;
#define INF 0x3f3f3f3f
const int maxn=(1<<17)+3;
const ll maxv=1e18+1;
const int MAXN=1e3+10;
const long long mod=100000000;
using namespace std;
ll dp[maxn][3],x[maxn],y[maxn];
char s[maxn],a[maxn],b[maxn],t[maxn];
int n;
int main(int argc, char const *argv[])
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int T;
cin>>T;
while(T--)
{
scanf("%d",&n);
scanf("%s%s%s",s+1,a+1,b+1);
for(int i=1;i<=n;i++) t[i]=(s[i]=='0')?'1':'0';
t[1]++;
for(int i=1;i<=n;i++)
{
if(t[i]=='2')
{
t[i]='0',t[i+1]++;
}
}
t[n+1]='0';
x[0]=-1,y[0]=-1;
for(int i=1;i<=n;i++)
{
if(a[i]=='0') x[i]=1;
else
{
x[i]=(x[i-1]==-1)?-1:(x[i-1]<<1);
x[i]=min(maxv,x[i]);
}
if(b[i]=='0') y[i]=1;
else
{
y[i]=(y[i-1]==-1)?-1:(y[i-1]<<1);
y[i]=min(maxv,y[i]);
}
}
for(int i=0;i<=n+1;i++) dp[i][0]=INF,dp[i][1]=INF;
dp[0][0]=0,dp[0][1]=0;
for(int i=1;i<=n;i++)
{
if(s[i]=='0')
{
dp[i][0]=min(dp[i][0],dp[i-1][0]);
if(x[i]!=-1) dp[i][0]=min(dp[i][0],dp[i-1][1]+x[i]);
}
else if(x[i]!=-1) dp[i][0]=min(dp[i][0],dp[i-1][0]+x[i]);
if(t[i]=='0')
{
dp[i][1]=min(dp[i][1],dp[i-1][1]);
if(y[i]!=-1) dp[i][1]=min(dp[i][1],dp[i-1][0]+y[i]);
}
else
{
if(y[i]!=-1) dp[i][1]=min(dp[i][1],dp[i-1][1]+y[i]);
}
}
printf("%lld\n",min(dp[n][0],dp[n][1]+1));//如果采用最后一位是减的话,那么一定要加一位更高位的1
}
return 0;
}