题目链接:http://codeforces.com/contest/779/problem/E
题意:有n个变量都可以用m位二进制数表示,这n个数的value将以两种格式中的一种给出
1.变量名, 空格, ":=", 空格, 一个正好m位的二进制数
eg(m = 3): a := 101
2.变量名, 空格, ":=", 空格, 第一个变量, 空格, 位运算符(AND,OR,XOR), 空格, 第二个变量
每一个变量都是前面被定义过的变量或者用 '?'表示
eg: aaa := a AND aa
bbb := b XOR ?
你需要确定'?'这个m位的二进制数,并输出使n个数总和最小和最大时的'?'
maxn = 5000
maxm = 1000
解法:一个稍复杂的二进制模拟题
'?'这个二进制数的m位每一位都有2种可能
所以与'?'有关的所有变量的二进制表示中每一位最多都有2种可能
注意到第二种读入中可能某个变量的值与'?'有关,后面这个变量又会参与运算
所以我们当计算第 i 个数时,需要保证前i - 1个数都已经被计算出来
所以解题思路就是直接计算出所有变量
然而如果读入一个算式立即用if各种判断的话,写出来会很丑很长
我们需要考虑简化代码 (参考了rank2的代码
注意到我们如果循环读入一个变量立刻计算其value需要O(nm)的空间
转化为全部读入后再一位一位的处理只需要O(n)的空间
我们可以v1和v2表示参与运算的变量的标号('?'被表示为第n+1个变量)
并用op来记录是哪种位运算符,最后统一处理就方便了很多
(string+map大法好
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 map <string, int> p; 6 7 int n, m, c[2]; 8 9 int s[2][5010]; 10 11 struct node { 12 int op; 13 int v1, v2; 14 string s; 15 }a[5010]; 16 17 int main() { 18 string s1, s2, s3, s4, s5, ansmin = "", ansmax = ""; 19 20 scanf("%d %d", &n, &m); 21 for(int i = 1;i <= n;i ++) { 22 cin >> s1 >> s2 >> a[i].s, p[s1] = i; 23 if(a[i].s[0] == '0' || a[i].s[0] == '1') continue; 24 if(a[i].s[0] == '?') a[i].v1 = n + 1; 25 else a[i].v1 = p[a[i].s]; 26 27 cin >> s4 >> s5; 28 switch(s4[0]) { 29 case 'A':a[i].op = 1;break; 30 case 'O':a[i].op = 2;break; 31 case 'X':a[i].op = 3;break; 32 } 33 if(s5[0] == '?') a[i].v2 = n + 1; 34 else a[i].v2 = p[s5]; 35 } 36 37 s[0][n + 1] = 0, s[1][n + 1] = 1; 38 for(int i = 0;i < m;i ++) { 39 c[0] = 0, c[1] = 0; 40 for(int k = 0;k < 2;k ++) { 41 for(int j = 1;j <= n;j ++) { 42 switch(a[j].op) { 43 case 0:s[k][j] = a[j].s[i] - '0';break; 44 case 1:s[k][j] = s[k][a[j].v1] & s[k][a[j].v2];break; 45 case 2:s[k][j] = s[k][a[j].v1] | s[k][a[j].v2];break; 46 case 3:s[k][j] = s[k][a[j].v1] ^ s[k][a[j].v2];break; 47 } 48 if(s[k][j]) c[k] ++; 49 } 50 } 51 ansmin += c[0] <= c[1] ? '0' : '1'; 52 ansmax += c[0] >= c[1] ? '0' : '1'; 53 } 54 55 cout << ansmin << ' ' << ansmax; 56 return 0; 57 }