• 巴厘岛的雕塑 BZOJ 4069


    巴厘岛的雕塑


    题解:

    题意是要求分组使每组的和按位取或的值最小

    那么考虑贪心,尽量使高位为0

    于是枚举位置,从最高位枚举

    假设当前枚举到第l位。

    令 f[i][j] 表示前 i 个数分成 j 组,满足前l - 1位的最优答案,当前这一位能否填0

    则 f[i][j] = true 当且仅当存在 k 满足 f[k][j - 1] = true 且 (sum[i] - sum[k]) | ans == ans 且 ((sum[i] - sum[k]) >> (l - 1)) & 1 == 0

    然后判断f[n][i]中是否有等于true的项,更新临时答案

    最后一组数据过大,所以需要特别处理

    令g[i]表示前i个数满足临时答案的最少组数

    则g[k]能转移到g[i]当且仅当 (((sum[i] - sum[k]) | ans) == ans 且 (((sum[i] - sum[k]) >> (l - 1)) & 1) == 0)

    如上更新答案

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    inline int Get()
    {
        int x = 0;
        char c = getchar();
        while('0' > c || c > '9') c = getchar();
        while('0' <= c && c <= '9')
        {
            x = (x << 3) + (x << 1) + c - '0';
            c = getchar();
        }
        return x;
    }
    const int me = 2001;
    long long ans;
    int len;
    int g[me];
    long long sum[me];
    bool f[101][101];
    int n, a, b, c;
    int main()
    {
        n = Get(), a = Get(), b = Get();
        for(int i = 1; i <= n; ++i)
        {
            c = Get();
            sum[i] = sum[i - 1] + c;
        }
        len = log2(sum[n]) + 1;
        if(a - 1)
        {
            for(int l = len; l >= 1; --l)
            {
                f[0][0] = true;
                for(int i = 1; i <= n; ++i)
                    for(int j = 1; j <= i; ++j)
                    {
                        f[i][j] = false;
                        for(int k = 0; k < i; ++k)
                        {
                            long long su = sum[i] - sum[k];
                            if(f[k][j - 1] && ((su >> l) | ans) == ans && ((su >> (l - 1)) & 1ll) == 0)
                            {
                                f[i][j] = true;
                                break;
                            }
                        }
                    }
                ans <<= 1;
                for(int i = a; i <= b; ++i)
                    if(f[n][i])
                    {
                        ans |= 1;
                        break;
                    }
                ans ^= 1;
            }
            printf("%I64d", ans);
        }
        else
        {
            for(int l = len; l >= 1; --l)
            {
                for(int i = 1; i <= n; ++i)
                {
                    g[i] = n + 1;
                    for(int k = 0; k < i; ++k)
                    {
                        long long su = sum[i] - sum[k];
                        if(((su >> l) | ans) == ans && ((su >> (l - 1)) & 1ll) == 0)
                            if(g[k] + 1 < g[i]) g[i] = g[k] + 1;
                    }
                }
                ans <<= 1;
                if(g[n] > b) ans ^= 1;
            }
            printf("%I64d", ans);
        }
    }
  • 相关阅读:
    eclipse导入基于maven的java项目后没有Java标志和没有maven Dependencies有解决办法
    centOS6.5 安装后无法启动无线上网
    centOS6.5 关闭关盖待机
    centOS6.5 usr/src/kernels下为空
    python求两个列表的并集.交集.差集
    二叉树遍历
    python实现单链表的反转
    关系型数据库和非关系型数据库的区别和特点
    python 实现快速排序(面试经常问到)
    golang 切片和map查询比较
  • 原文地址:https://www.cnblogs.com/lytccc/p/6305353.html
Copyright © 2020-2023  润新知