題目大意:
給定一個長度爲 n 的僅包含’0’、’1’、’?’ 的字符串,你需要給所有的問號決定填 0 還是 1。
填完之後,將這個串看成二進制數,轉化成格雷碼。
如果格雷碼中第 i 個字符是 1,那麼你將獲得 ai 點分數。求可以得到的 分數的最大值。
1 ≤n≤ 200000,1 ≤ai ≤ 1000。
Source:2015 Multi-University Training Contest 7
From Claris
分析:
PS:二進制碼轉換爲格雷碼的方法爲將二進制碼右移一位然後與 原來的二進制碼按位異或。
簡單數位dp
設dp[i][0/1] :表示考慮前i位,第i位填0/1所得的最大分數和
如果第i位爲’?’,有:
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+a[i]);
dp[i][1]=max(dp[i-1][1],dp[i-1][0]+a[i]);
如果當前位已確定,看前一位是否確定,根據前一位的狀態轉移。
注意非法狀態不能要!!
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 200000
#define INF 2000000000
typedef long long LL;
int n,a[MAXN+10];
LL dp[MAXN+10][2];
char s[MAXN+10];
int main()
{
int T;
scanf("%d",&T);
for(int k=1;k<=T;k++){
scanf("%s",s+1);
int n=strlen(s+1);
s[0]='0';
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
memset(dp,0,sizeof dp);
dp[0][1]=-INF;
for(int i=1;i<=n;i++){
if(s[i]=='?'){
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+a[i]);
dp[i][1]=max(dp[i-1][1],dp[i-1][0]+a[i]);
}
else{
if(s[i-1]!='?'){
if(s[i]!=s[i-1]){
dp[i][s[i]-'0']=dp[i-1][s[i-1]-'0']+a[i];
dp[i][1-(s[i]-'0')]=-INF;
}
else{
dp[i][s[i]-'0']=dp[i-1][s[i-1]-'0'];
dp[i][1-(s[i]-'0')]=-INF;
}
}
else{
dp[i][1-(s[i]-'0')]=-INF;
dp[i][s[i]-'0']=max(dp[i-1][s[i]-'0'],dp[i-1][1-(s[i]-'0')]+a[i]);
}
}
}
printf("Case #%d: %lld\n",k,max(dp[n][0],dp[n][1]));
}
}