嵊州D5T3 指令 program 神奇的位运算

指令 program

【问题描述】

krydom 有一个神奇的机器。

一开始,可以往机器里输入若干条指令: opt x 其中,opt 是 & | ^ 中的一种,0 ≤ x ≤ 1023 。

对于 0 到 1023 的每一个数 m,机器会输出 m 按照指令依次运算后的结果。

现在,krydom 往里面输入了 n 条指令,但是 zcysky 觉得 krydom naive, 只用 3 条指令就实现了和这 n 条指令一样的功能。

由于 krydom 很菜,希望你们帮帮他,但是只需要输出 5 条以内的指令就行了。

【输入格式】

第一行包括一个整数 n,表示指令的个数。 接下来 n 行,每行一个字符 opt 和一个数字 x,表示 ans = ans opt x

【输出格式】

第一行输出一个整数 m,表示有 m 条新指令。(要求 m ≤ 5)

接下来 m 行,每行一个字符 opt 和一个数字 x。表示一条新指令。

【输入输出样例】

Input1 Input2 Input3

3

| 3

^ 2

| 1

3

&1

& 3

& 5

3

^ 1

^ 2

^ 3

Output1 Output2 Output3

2

| 3

^ 2

1

& 1

0

 

【样例解释】

样例 2 解释:

((x&1)&3)&5 = x&(1&3&5) = x&1

样例 3 解释:

((x^1)^2)^3 = x^(1^3^4) = x^0 = x

【数据范围】

对于 20% 的数据满足: n ≤ 5 。

对于 50% 的数据满足: x ≤ 3 。

对于 100%的数据满足: n ≤ 5*10^5

吐槽

这是道使人有很多想法的题目呢

当我看到位运算是,我想到的是<bitset>……------------STL大法好!

后来,发现不需要那些高级函数和类方法,反倒觉得是搜索

因为我只要从一个数出发,能通过三种运算,得到最终结果即可

DFS

#include<bits/stdc++.h>
using namespace std;
char opt1,opt2[6];
int first=1023;
int num2[6],ch=first,flag=0;//ch:目标状态 
void dfs(int nowch,int depth){//nowch:dfs现在状态 
    if(depth>5) return;//(要求m ≤ 5)
    if(flag==1) return;
    //是否成功 
    if(ch==nowch) {
        cout<<depth<<endl;
        for(int i=0;i<depth;i++)
            cout<<opt2[i]<<" "<<num2[i]<<endl; 
        flag=1;
        return;
    } 
    //三种方法
    for(int i=1;i<=1023;i++){
        num2[depth]=i;
        opt2[depth]='&';
        dfs(nowch&i,depth+1);
        opt2[depth]='|';
        dfs(nowch|i,depth+1);
        opt2[depth]='^';
        dfs(nowch^i,depth+1);
        num2[depth]=0;
    }
    return;
}
int main(){
//    freopen("program.in","r",stdin);
//    freopen("program.out","w",stdout);
    int n; cin>>n;
    int num1[n],ans=n;
    for(int i=0;i<n;i++) {
        cin>>opt1;
        cin>>num1[i];    
        if(opt1=='&')
            ch&=num1[i]; 
        if(opt1=='|')
            ch|=num1[i];
        if(opt1=='^')
            ch^=num1[i];
    }
    dfs(first,0); 
    return 0;
} 

后来发现,DFS可以是可以,但是那个first不能仅仅是一个数

否则,除了一些特殊解,得到的答案可能是错的(非常错!错到离谱!)

因为没有人知道,那台机器到底是按哪个数作为标准的

何况,它会把1到1023(1111111111)全输出

按道理说吧,那基础的几十分总是能拿到的吧?

但是,dfs最大的敌人,就是还没搜到就超时了。。。

于是,我们就惊讶的看到了std。。。

std

 1 #include <cstdio>
 2 #define FOR(i, l, r) for(int i = l; i <= r; ++i)
 3 using namespace std;
 4 int n, x, y, opt, f[11];
 5 char s[5];
 6 //用来表示 and& or| xor^ 
 7 int work(int now, int opt)
 8 {
 9     if (opt == 1) return 0;//如果是&,返回0 
10     if (opt == 2) return 1;//如果是|,返回1 
11     if (now <= 1) return now ^ 1;//如果now小于等于1,返回now对1按位异或 
12         else return 5 - now;//now大于1,返回0101-now 
13 }
14 int output(int x)
15 {
16     int ans = 0;//每次输出结果先归0 
17     for(int i = 10; i; --i)
18     {
19         ans <<= 1;//每次把ans左移一位,差不多相当于是自乘2 (0左移一位(或者说是*2)还是0哟) 
20         if (f[i] == x) ans |= 1;//如果f[10~1]等于x(输进来的数),就把ans按位或于1,即把最低位变成1 
21     }
22     return ans;
23 }
24 int main()
25 {
26 //    freopen("program.in", "r", stdin);
27 //    freopen("program.out", "w", stdout);
28     
29     FOR(i, 1, 10) f[i] = 2;
30     scanf("%d", &n);
31     FOR(i, 1, n)
32     {
33         scanf("%s%d", s, &x);//输入 
34         if (s[0] == '&') opt = 1; else//分别用1,2,3来存储& | ^ 
35         if (s[0] == '|') opt = 2; else opt = 3;
36         FOR(j, 1, 10)
37         {
38             y = x & 1;//把x与1按位与的值赋给y 
39             if (opt == 1 && !y) f[j] = work(f[j], 1);
40             if (opt != 1 && y) f[j] = work(f[j], opt);
41             x >>= 1;
42         }
43     }
44     puts("3");//固定输出3,方便与三个符号都有操作 
45     printf("& %d\n", output(0) ^ 1023);//把结果与1111111111取按位异或 
46     printf("| %d\n", output(1));
47     printf("^ %d\n", output(3));
48     //其实只要m<=5就好了,但是这是最简单的方法 
49     return 0;
50 }

std的解析都在注释里了。

因为这道题是SPJ,所以就算输出后面跟着的是0也行,不输出也行。

这种方法也告诉我们,多种位运算是可以用三种位运算表示滴~

有木有感觉很神奇?

posted @ 2019-07-15 20:35  Vanilla_chan  阅读(287)  评论(0编辑  收藏  举报