hdu 5375 Gray code (dp)
tags: acm
今年多校的一道简单题.做之前和队友讨论了一下,成功说服队友这题贪心可破,结果我敲的时候却强行dp过了╮(╯▽╰)╭不过后来队友又用贪心过了一遍,貌似比我的代码快一点点.话说我很好奇要是不知道二进制转格雷码的方式的话这题要怎么玩?
题意:
给你一个字符串B,B中包含’0’,’1’及’?’,其中’?’代表这位不确定,可能为’0’也可能为’1’.同时给你一个与B的长度相同的数组A( 1≤ai≤1000 ).问,如果将这个字符串对应的二进制数(由于存在’?’,可能对应多个二进制数),转化为等长的代表格雷码的01串G后,求 ∑ci∗ai 的最大值.
标准格雷码的性质:二进制a1 a2 … an,对应的格雷码为a1 (a1 xor a2) … (an-1 xor an)
解析:
使用dp[i][j]表示当取到第i位且这一位为j的最大分数,则有:
若B[i]=='0'
则分别考虑B[i-1]为’0’,’1’,’?’的情况,分别更新dp[i][0]和dp[i][1] (此时dp[i][1]为0,因为当前位已经确定是’0’)
B[i]=='1'
时同理,而B[i]=='?'
时结合前面两种情况更新.
最后max(dp[N-1][0],dp[N-1][1])
即为所求的最大值.
代码:
312ms
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
#define MAXN 200000+1000
int N;
char B[MAXN];
int A[MAXN];
int dp[MAXN][2];
int max(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int T;
int cas = 1;
scanf("%d", &T);
getchar();
while (T--)
{
scanf("%s", B);
int N = strlen(B);
for (int i = 0; i < N; i++)
{
scanf("%d", &A[i]);
}
dp[0][0] = 0;
dp[0][1] = 0;
if (B[0] == '1' || B[0] == '?')
{
dp[0][1] = A[0];
}
for (int i = 1; i < N; i++)
{
if (B[i] == '0')
{
dp[i][1] = 0;
if (B[i - 1] == '0')
dp[i][0] = dp[i - 1][0];
else if (B[i - 1] == '1')
dp[i][0] = dp[i - 1][1] + A[i];
else
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + A[i]);
}
else if (B[i] == '1')
{
dp[i][0] = 0;
if (B[i - 1] == '0')
dp[i][1] = dp[i - 1][0] + A[i];
else if (B[i - 1] == '1')
dp[i][1] = dp[i - 1][1];
else
dp[i][1] = max(dp[i - 1][0] + A[i], dp[i - 1][1]);
}
else
{
//=======
if (B[i - 1] == '0')
dp[i][0] = dp[i - 1][0];
else if (B[i - 1] == '1')
dp[i][0] = dp[i - 1][1] + A[i];
else
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + A[i]);
//=======
if (B[i - 1] == '0')
dp[i][1] = dp[i - 1][0] + A[i];
else if (B[i - 1] == '1')
dp[i][1] = dp[i - 1][1];
else
dp[i][1] = max(dp[i - 1][0] + A[i], dp[i - 1][1]);
}
}
printf("Case #%d: ", cas++);
int ans = max(dp[N - 1][0], dp[N - 1][1]);
printf("%d\n", ans);
}
return 0;
}