给你一个二进制数,,每一位有一个权值,让你转格雷码,求所对应格雷码位为1的权值的和;二进制位中的某些位为?,你需要给这些问号赋值使得到的和最大。
首先你得知道二进制转格雷码的规则,即格雷码位为【二进制位与左边前一位的异或值】,格雷码首位为二进制首位;
因为格雷码首位为二进制首位,那么可以视二进制首位的左边前一位是0;
然后你就可以分情况模拟了:
1、连续数字的情况直接计算即可;
2、连续问号的情况需要dp一下:dp[k][j]表示第k个问号是j时,得到的最大和,那么dp[k][j] = max(dp[k-1][!j]+w[i], dp[k-1][j]);首尾的细节处要处理好;
这里也可以不用dp直接模拟求,需要分一下问号数的奇偶性,比较复杂不再讨论了;
附代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<queue> 7 using namespace std; 8 typedef long long ll; 9 const int maxn = 200005; 10 char bin[maxn]; 11 int w[maxn]; 12 int dp[maxn][3]; 13 14 int main() 15 { 16 int T; 17 scanf("%d", &T); 18 for(int kase = 1; kase <= T; kase++) 19 { 20 scanf("%s", bin+1); 21 bin[0] = '0'; 22 int len = strlen(bin+1); 23 for(int i = 1; i<= len; i++) 24 scanf("%d", &w[i]); 25 26 int ans = 0, i = len; 27 while(i >= 1) 28 { 29 if(bin[i] != '?') 30 { 31 if(bin[i-1] == '?') // X????1 连问号且尾接数字,dp[i][j]为(从右向左问号的)第i位为j时最大值:dp[i][j] = (dp[i][!j]+w[i] , dp[i][j]); 32 { 33 int pos = 1; //注意结尾的数字要单独考虑,结尾(bin[i])是1,则dp[1][0]=w[i],dp[1][1]=0;是0,则dp[1][1]=w[i],dp[1][0]=0 34 dp[pos][0] = w[i]*((bin[i]-'0')^0); 35 dp[pos][1] = w[i]*((bin[i]-'0')^1); 36 pos++; i--; //i指向当前考虑的格雷码位,pos指向i的前一位对应的从右向左的第几个'?' 37 while(i && bin[i-1] == '?') 38 { 39 dp[pos][0] = max(dp[pos-1][1] + w[i], dp[pos-1][0]); 40 dp[pos][1] = max(dp[pos-1][0] + w[i], dp[pos-1][1]); 41 pos++; i--; 42 } 43 //前面的数字也要单独考虑,若bin[i-1]是1,则max_val=max(dp[pos-1][0] + w[i], dp[pos-1][1]); 44 dp[pos][bin[i-1] - '0'] = max(dp[pos-1][!(bin[i-1] - '0')] + w[i], dp[pos-1][bin[i-1] - '0']); 45 ans += dp[pos][bin[i-1] - '0']; 46 i--; 47 } 48 else // X11111 连数字,直接与前一位异或计算即可 49 { 50 while(i && bin[i-1] != '?') 51 { 52 ans += ((bin[i]-'0')^(bin[i-1]-'0')) * w[i]; 53 i--; 54 } 55 } 56 } 57 else // X???? 连问号且尾不接数字,可以保证其格雷码'?'处全为1 58 { 59 while(i && bin[i] == '?') 60 { 61 ans += w[i]; 62 i--; 63 } 64 } 65 } 66 printf("Case #%d: %d ", kase, ans); 67 } 68 return 0; 69 }
最近易激动,大约是亲戚来的缘故吧。有点想家了。
加油吧,在这个优胜劣汰的游戏中,努力生存下去吧。