zoukankan      html  css  js  c++  java
  • BZOJ

    题意:

      给定N个数,一个数k和一个范围[L,R]。每个数可以使用任意次,k表示与非不超过k位。求出范围内有多少个数可以由他们的与非和表示。

    题解:

      m个数进行NAND,最终的数二进制下某一位如果为1,那么这m个数二进制下这一位也肯定为1。所以如果N个数某些位相同的话就可以把这些位并成一个基。

      因为aNANDa = !a,所以某一位如果为0可以转化为1。

      然后用预处理的基从高位开始贪心的选择。如果当前位取0,则情况数为(1<<cnt-i)-1(不包含0);当前位取1时情况数为1。一共是(1<<cnt-i)。

      题目中L的范围给错了,可能为0。所以当L为0时应该+1即-(-1)。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1005;
    int n, k, cnt;
    ll l, r, noww;
    int vis[N];
    ll a[N], w[70];
    ll digit(ll x) {
        if(x==-1) return -1;
        ll res = 0, val = 0;
        for(int i = 1; i <= cnt; i++) {
            if(val+w[i] <= x) {
                val += w[i];
                res += (1ll<<cnt-i);
            }
        }
        return res;
    }
    int main() {
        scanf("%d%d%lld%lld", &n, &k, &l, &r);
        for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
        noww = (1ll<<k)-1;
        for(int i = k-1; i >= 0; i--) {
            if(vis[i]) continue;
            ll ed = noww;
            for(int j = 1; j <= n; j++) 
            if(a[j]&(1ll<<i)) ed &= a[j];
            else ed &= (~a[j]);
            for(int j = 0; j < i; j++) if(ed&(1ll<<j)) vis[j] = 1;
            w[++cnt] = ed;
        }
        printf("%lld", digit(r) - digit(l-1));
    }
    View Code
  • 相关阅读:
    MVC视图布局页常用代码
    常用meta标签及说明
    重新认识Android
    为什么V8引擎这么快?
    node.js入门及express.js框架
    红星美凯龙CEO车建新的圆融和霸气
    【一个王朝的背影】--余秋雨
    Android源代码结构分析
    Android文件系统的结构
    Mac OSX 平台安装 MongoDB
  • 原文地址:https://www.cnblogs.com/Pneuis/p/9090239.html
Copyright © 2011-2022 走看看