CodeForces 778B Bitwise Formula 解题报告

题目:http://codeforces.com/problemset/problem/778/B
题意:给出n个变量的表达式,表达式可含有变量名、长度为m的二进制数和“?”

输入样例1:
3 3
a := 101
b := 011
c := ? XOR b

输入样例2:
5 1
a := 1
bb := 0
cx := ? OR a
d := ? XOR ?

其中,所有的“?”是同一个长度为m的二进制数
现在求使得所有变量之和最小、最大的两个“?”(如果有多个相同答案,取字典序最小的一个)

数据范围:(1 ≤ n ≤ 5000; 1 ≤ m ≤ 1000) 可见 2^1000 的暴力做法是不可取的,
但题目中的三种位运算符 “AND”“OR”“XOR”都不会造成进位,因此“?”的第i位的值是不会对其他位的运算结果产生影响的。

题解:
其实这是一道 字符串处理题 拆位题
枚举每一位取‘0’或‘1’然后取最值就可以了

代码(字符串处理比较麻烦):

#include <cstdio>
#include <cstring>

int n,m,i,j,res1,res2;
char str[1010],min[1010],max[1010];

struct var {
    bool *ans,*l,*r;//bool* 表示二进制数,l,r 表示运算符左边和右边的变量或二进制数,把计算结果储存在ans里
    char mode,name[15];//name 变量名 mode 为运算方式'A','O','X','C'(没有运算的赋值)
} v[5010];

bool *init(char *s) {//处理一个变量名或二进制数,返回bool数组指针
    if (*s > '1') for (int i=0;i<=n;i++) if (!strcmp(s,v[i].name)) return v[i].ans;
    bool *b = new bool[m];
    for (int i=0;i<m;i++) b[i] = s[i] - '0';
    return b;
}

int calc(var *u,int t) {//对u的第t位求值,返回0或1
    switch (u->mode) {
        case 'A' :  return (u->ans[t] = u->l[t] && u->r[t]) ? 1 : 0;  break;
        case 'O' :  return (u->ans[t] = u->l[t] || u->r[t]) ? 1 : 0;  break;
        case 'X' :  return (u->ans[t] = u->l[t] ^  u->r[t]) ? 1 : 0;  break;
        default : return (u->ans[t]) ? 1 : 0; break;
    }
}

int main() {
    scanf("%d%d",&n,&m);
    v[0].name[0] = '?';  v[0].ans = new bool[m];//v[0]为“?”变量
    for (i=1;i<=n;i++) {//读入表达式并处理到v数组
        scanf("%s := %[^\n]",v[i].name,str);
        char *s = str;
        while (*s != 'A' && *s != 'O' && *s != 'X' && *s) s++;
        v[i].mode = (*s) ? *s : 'C';
        if (!*s) {v[i].ans = init(str);  continue;}
        v[i].l = init(str);
        v[i].r = init(strstr(s+1," ") + 1);
        v[i].ans = new bool[m];
    }

    for (i=0;i<m;i++) {//枚举每一位在每个变量中的值,判断01
        for (j=1,v[0].ans[i] = true ;j<=n;j++) res1 += calc(v+j,i);
        for (j=1,v[0].ans[i] = false;j<=n;j++) res2 += calc(v+j,i);
        min[i] = (res1 >= res2) ? '0' : '1';
        max[i] = (res1 <= res2) ? '0' : '1';
        res1 = res2 = 0;
    }
    puts(min);  puts(max);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值