这题倒是不难,然而被笔误折腾死了TAT还被无良队友坑了两顿大餐~~
做法有两种我都尝试了一下。
第一种是动态规划,用dp[n][2]的数组,0、1分别是可能的数字,不能取0或1时赋值为-1作为标识。状态转移很好理解,方程看程序一即可。
第二种比较巧,算贪心吧?(就是这题笔误WA了好几遍TAT)
由于每一位对应价值都是正整数,当然取越多越好,数值已定的数位无法改变,而?的位置则尽量保证将数字串变成01交替,这样转成格雷码就全是1了。而根据问号个数和前后的数字,不可能每次都正好转成01交替,如果不能,则会有一位上数字叠一次,那么为损失最小,让这些位上价值最小的与前一位叠一样的数,可保最优。写的时候比思路更简单,直接全加上,如果需要叠一位,找到最小的减掉就行了,并不用真的模拟构造数字串。具体看程序二。
//程序一
#include<iostream>
#include<cstdio>
using namespace std;
char str[200005];
int dp[200005][2];
int a[200005];
int main()
{
int T,TT,n,i;
scanf("%d",&T);TT=1;
while(T--)
{
getchar();
scanf("%s",str+1);
n=1;
while(str[n]!='\0')
{
scanf("%d",&a[n]);n++;
}
n--;
//--------------------------------------------------------------------------
for(i=1;i<=n;i++)
dp[i][0]=dp[i][1]=-1;
if(str[1]=='?')
{
dp[1][0]=0;dp[1][1]=a[1];
}
else if(str[1]=='1')
dp[1][1]=a[1];
else dp[1][0]=0;
//--------------------------------------------------------------------------
for(i=2;i<=n;i++)
if(str[i]=='?')
{
if(dp[i-1][1]!=-1)
{
dp[i][0]=max(dp[i-1][1]+a[i],dp[i][0]);
dp[i][1]=max(dp[i-1][1],dp[i][1]);
}
if(dp[i-1][0]!=-1)
{
dp[i][0]=max(dp[i-1][0],dp[i][0]);
dp[i][1]=max(dp[i-1][0]+a[i],dp[i][1]);
}
}
else if(str[i]=='1')
{
if(dp[i-1][1]!=-1) dp[i][1]=max(dp[i-1][1],dp[i][1]);
if(dp[i-1][0]!=-1) dp[i][1]=max(dp[i-1][0]+a[i],dp[i][1]);
}
else
{
if(dp[i-1][1]!=-1) dp[i][0]=max(dp[i-1][1]+a[i],dp[i][0]);
if(dp[i-1][0]!=-1) dp[i][0]=max(dp[i-1][0],dp[i][0]);
}
//--------------------------------------------------------------------------------
printf("Case #%d: ",TT);TT++;
if(str[n]=='?') printf("%d\n",max(dp[n][0],dp[n][1]));
else if(str[n]=='1') printf("%d\n",dp[n][1]);
else printf("%d\n",dp[n][0]);
}
return 0;
}
//程序二
#include<iostream>
#include<cstdio>
using namespace std;
int a[200005];
char str[200005];
int main()
{
int T,TT,n,i,j,sum,posl,ans,mi;
scanf("%d",&T);TT=1;
while(T--)
{
scanf("%s",str+1);
str[0]='0';
n=1;
while(str[n]!='\0')
{
scanf("%d",&a[n]);n++;
}
n--;posl=0;ans=0;sum=0;
for(i=1;i<=n;i++)
if(str[i]=='?')
{
ans++;
if(ans==1) posl=i;
}
else
{
if(posl!=0)
{
if(posl==1)
{
for(j=posl;j<=i;j++) sum=sum+a[j];
if((str[i]=='1'&&ans%2==1)||(str[i]=='0'&&ans%2==0))
{
mi=a[posl];
for(j=posl+1;j<=i;j++)
if(mi>a[j]) mi=a[j];
sum=sum-mi;
}
}
else
{
for(j=posl;j<=i;j++) sum=sum+a[j];
if((str[i]==str[posl-1]&&ans%2==0)||(str[i]!=str[posl-1]&&ans%2==1))
{
mi=a[posl];
for(j=posl+1;j<=i;j++)
if(mi>a[j]) mi=a[j];
sum=sum-mi;
}
}
posl=0;ans=0;
}
else
{
if(str[i]!=str[i-1]) sum=sum+a[i];
}
}
if(ans!=0)
{
for(j=posl;j<=n;j++) sum=sum+a[j];
}
printf("Case #%d: %d\n",TT,sum);TT++;
}
return 0;
}