HDU5375 格雷码

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;
}

你可能感兴趣的:(HDU5375 格雷码)