位运算

1、UOJ 【NOI2014】起床困难综合症

参考:http://blog.csdn.net/kiana810/article/details/38226665

解题思路:

位运算各位之间的计算互不影响

所以可以按位从高到低贪心来做

贪心策略:

①在枚举前面的位数时,出现了 m 这一位上为 1 且选 0 时结果大于等于选 1 的结果,那么以后的答案的每一位就是选 0/1 的结果的最大值
②没有出现①中的情况,且 m 的这一位为 0,那么答案的这一位就是选 0 的结果
③没有出现①中的情况,且 m 的这一位为 1,如果这个时候选 0 时结果大于等于选 1 的结果,答案的这一位就是选 0 的结果,然后标记一下,以后的每一位就得都按情况①来考虑了,否则这一位就是选 1 的结果
答案的二进制的每一位已知,转换为十进制就好了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <cmath>
#include <cctype>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;

const ull mod = 1e9 + 7;
const ull INF = 0x4000000000000;
int B_m[100], _1_m[100], _0_m[100];
int ans[100];

void Operator(int n, int key);

int main()
{
#ifdef __AiR_H
    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
#endif // __AiR_H
    int n;
    uint m;
    scanf("%d%d", &n, &m);
    char op[5];
    int t;
    for (int i = 0; i <= 50; ++i) {
        _0_m[i] = 0;
    }
    for (int i = 0; i <= 50; ++i) {
        _1_m[i] = 1;
    }
    for (int i = 0; i < n; ++i) {
        scanf("%s%d", op, &t);
        if (op[0] == 'A') {
            Operator(t, 1);
        } else if (op[0] == 'O') {
            Operator(t, 2);
        } else {
            Operator(t, 3);
        }
    }
    for (int i = 0; i <= 50; ++i) {
        B_m[50 - i] = m % 2;
        m /= 2;
    }
    bool flag = false;
    for (int i = 0; i <= 50; ++i) {
        if (flag) {
            ans[i] = max(_0_m[i], _1_m[i]);
        } else if (B_m[i] == 0) {
            ans[i] = _0_m[i];
        } else {
            if (_0_m[i] >= _1_m[i]) {
                flag = true;
                ans[i] = _0_m[i];
            } else {
                ans[i] = _1_m[i];
            }
        }
    }
    ull ans_last = 0;
    ull key_t = INF;
    for (int i = 0; i <= 50; ++i) {
        ans_last += key_t*ans[i];
        key_t >>= 1;
    }
    printf("%llu\n", ans_last);
    return 0;
}

void Operator(int n, int key)
{
    for (int i = 0; i <= 50; ++i) {
        int t = n%2;
        if (key == 1) {
            _0_m[50 - i] &= t;
            _1_m[50 - i] &= t;
        } else if (key == 2) {
            _0_m[50 - i] |= t;
            _1_m[50 - i] |= t;
        } else {
            _0_m[50 - i] ^= t;
            _1_m[50 - i] ^= t;
        }
        n /= 2;
    }
}

2、HDU 5745 La Vie en rose

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <cmath>
#include <cctype>
#include <bitset>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;

const ull mod = 1e9 + 7;
const int INF = 0x7fffffff;
const int maxn = 1e5 + 10;
int n, m;
char s[maxn], p[6000];
bitset<maxn> bs[3], w[26];

int main()
{
#ifdef __AiR_H
    freopen("in.txt", "r", stdin);
#endif // __AiR_H
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        scanf("%s%s", s, p);
        for (int i = 0; i < 3; ++i) {
            bs[i].reset();
        }
        for (int i = 0; i < 26; ++i) {
            w[i].reset();
        }
        for (int i = 0; i < n; ++i) {
            w[s[i]-'a'][i] = 1;
            bs[0][i] = 1;
        }
        for (int i = 0; i < m; ++i) {
            int t1 = p[i] - 'a';
            bs[(i+1)%3] = bs[i%3] & (w[t1] >> i);
            if (i > 0) {
                int t2 = p[i-1] - 'a';
                bs[(i+1)%3] |= bs[(i+2)%3] & (w[t2] >> i) & (w[t1] >> (i-1));
            }
        }
        for (int i = 0; i < n; ++i) {
            if (bs[m%3][i] == 1) {
                printf("1");
            } else {
                printf("0");
            }
        }
        printf("\n");
    }
    return 0;
}


3、HDU 5969 最大的位或

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

typedef unsigned long long ull;

int T;
ull l, r;
int key1[100], key2[100];
bool vis[100];

int main()
{
#ifdef Floyd
    freopen("in.txt", "r", stdin);
#endif // Floyd
    scanf("%d", &T);
    while (T--) {
        memset(vis, false, sizeof(vis));
        scanf("%lld %lld", &l, &r);
        ull ans = r;
        int cnt1 = 0;
        while (r) {
            int t = r % 2;
            key1[cnt1++] = t;
            r /= 2;
        }
        ull l_t = ((ull)1 << (cnt1 - 1)) - 1;
        if (l_t >= l) {
            ans = ((ull)1 << cnt1) - 1;
        } else {
            while (1) {
                key2[cnt1 - 1] = 1;
                for (int i = cnt1 - 2; i >= 0; --i) {
                    key2[i] = key1[i];
                    if (key1[i] == 1 && !vis[i]) {
                        vis[i] = true;
                        key2[i] = 0;
                        for (int j = i - 1; j >= 0; --j) {
                            key2[j] = 1;
                        }
                        break;
                    }
                }
                ull ans_t = 0;
                for (int i = 0; i < cnt1; ++i) {
                    ans_t += ((ull)1 << i) * key2[i];
                }
                if (ans_t >= l) {
                    ans |= ans_t;
                    break;
                }
            }
        }
        printf("%llu\n", ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值