HDU5375 Gray code
二进制如何转换成格雷码:给二进制左端第0位补上一个0,然后从第一位开始当前一位与后一位异或,依次得到的数字就组成格雷码,格雷码的哪一位就对应于原二进制的哪一位,比如二进制01001对应的格雷码就是01101
题意:把二进制c转换成格雷码,格雷码的每一位对应了一个值a,给的二进制里面含有问号,问号可以用1或0替换,然后求它转换的格雷码对应的值的和最大是多少,格雷码是1的地方对应的值a是有效的是0则无效,比如:
格雷码:01101
对应值:1 6 4 2 3
它的和就是6+4+3=13
思考了一会儿发现包含问号一个子串总共只有四种情况:
1.问号序列长为偶数,左右两端相同,如0??0
2.问号序列长为偶数,左右两端不同,如0??1
3.问号序列长为奇数,左右两端相同,如0???0
4.问号序列长为奇数,左右两端不同,如0???1
第2、3情况时问号序列对应值可以全部加起来
第1、4情况时问号序列不能全部加起来,难免要舍弃一个,所以舍弃最小的一个,其余加起来
对于零界状态再考虑,很简单
#include<cstdio>
#include<cstring>
char c[200005];//记录串
int a[200005];//记录值
int main(){
char ch;
int n,i,j,T;
scanf("%d",&T);
for(int t=1;t<=T;t++){
getchar();
c[0]='0';//因为编码的时候在前面补了一个0,所以索性让c[0]='0'
for(i=1;(ch=getchar())!='\n';)c[i++]=ch;
n=i-1;//n表示的是题目给的串长度(不包含前面补的0)
for(i=1;i<=n;i++)//让a下标从1开始是方便和c一一对应
scanf("%d",&a[i]);
int sum=0;
int count;//计算连续的问号有多少个
for(i=1;i<=n;i++){
int temp_sum=0;//一个问号序列对应的值的和
int min=100000;
int start_i=i;//记录问号序列的开始位置
for(count=0;i<=n&&c[i]=='?';i++){
count++;
temp_sum+=a[i];//临时把问号序列对应的值求和
if(a[i]<min)min=a[i];//找出问号序列的最小值
}//i到达了问号序列的末尾+1
if(i<=n){//如果问号序列不是到达串的结尾,那么它就属于这个问号序列
temp_sum+=a[i];//它的值要加起来
if(a[i]<min)min=a[i];//找最小值
}
if(count){//如果有问号序列
if(i==n+1)sum+=temp_sum;//当问号序列到达的结尾,最好的情况可以把序列和加起来
else if(count%2==1&&c[start_i-1]==c[i]||count%2==0&&c[start_i-1]!=c[i])sum+=temp_sum;
//当问号序列长度为奇数并且左右两端的数字是相同的时候
//或者当长度为偶数,左右不同的时候序列和全都可以加起来
else sum+=temp_sum-min;//但是当奇数且不同或偶数且相同的时候最好的情况
//也要舍弃其中一个数,就选最小的舍弃就行了
}
else if(i<=n&&c[i]!=c[i-1])sum+=a[i];//没有问号的情况很简单
}
printf("Case #%d: %d\n",t,sum);
}
return 0;
}