zoukankan      html  css  js  c++  java
  • [APIO2015]巴厘岛的雕塑

    题目描述

    印尼巴厘岛的公路上有许多的雕塑,我们来关注它的一条主干道。

    在这条主干道上一共有 NN 座雕塑,为方便起见,我们把这些雕塑从 11 到 NN 连续地进行标号,其中第 ii 座雕塑的年龄是 Y_iYi 年。为了使这条路的环境更加优美,政府想把这些雕塑分成若干组,并通过在组与组之间种上一些树,来吸引更多的游客来巴厘岛。

    下面是将雕塑分组的规则:

    这些雕塑必须被分为恰好 XX 组,其中 A leq X leq BAXB ,每组必须含有至少一个雕塑,每个雕塑也必须属于且只属于一个组。同一组中的所有雕塑必须位于这条路的连续一段上。

    当雕塑被分好组后,对于每个组,我们首先计算出该组所有雕塑的年龄和。

    计算所有年龄和按位取或的结果。我们这个值把称为这一分组的最终优美度。

    请问政府能得到的最小的最终优美度是多少?

    备注:将两个非负数 PP 和 QQ 按位取或是这样进行计算的:

    首先把 PP 和 QQ 转换成二进制。

    设 n_PnP 是 PP 的二进制位数, n_QnQ 是 QQ 的二进制位数, MM 为 n_PnP 和 n_QnQ 中的最大值。 PP 的二进制表示为 p_{M-1}p_{M-2} dots p_1p_0pM1pM2p1p0 , QQ 的二进制表示为 q_{M-1}q_{M-2} dots q_1 q_0qM1qM2q1q0 ,其中 p_ipi 和 q_iqi 分别是 PP 和 QQ 二进制表示下的第 ii 位,第 M -1M1 位是数的最高位,第 00 位是数的最低位。

    PP 与 QQ 按位取或后的结果是: (p_{M-1}mathbin{mathrm{OR}} q_{M-1})(p_{M-2}mathbin{mathrm{OR}}q_{M-2})dots (p_1mathbin{mathrm{OR}} q_1) (p_0mathbin{mathrm{OR}}q_0)(pM1ORqM1)(pM2ORqM2)(p1ORq1)(p0ORq0) 。其中: 0 mathbin{mathrm{OR}} 0 = 00OR0=0

    0 mathbin{mathrm{OR}} 1 = 10OR1=1

    1 mathbin{mathrm{OR}} 0 = 11OR0=1

    1 mathbin{mathrm{OR}} 1 = 11OR1=1

    输入输出格式

    输入格式:

    输入的第一行包含三个用空格分开的整数 N, A, BN,A,B 。

    第二行包含 NN 个用空格分开的整数 Y_1, Y_2, dots, Y_NY1,Y2,,YN 。

    输出格式:

    输出一行一个数,表示最小的最终优美度。

    输入输出样例

    输入样例#1: 复制
    6 1 3
    8 1 2 1 5 4
    输出样例#1: 复制
    11
    

    说明

    【样例解释】

    将这些雕塑分为 22 组, (8, 1, 2)(8,1,2) 和 (1, 5, 4)(1,5,4) ,它们的和是 (11)(11) 和 (10)(10) ,最终优美度是 (11 mathbin{mathrm{OR}} 10) = 11(11OR10)=11 。(不难验证,这也是最终优美度的最小值。)

    【数据范围】

    子任务 1 (9 分) 1 leq N leq 201N20

    1 leq A leq B leq N1ABN

    0 leq Y_i leq 10000000000Yi1000000000

    子任务 2 (16 分) 1 leq N leq 501N50

    1 leq A leq B leq min{20, N}1ABmin{20,N}

    0 leq Y_i leq 100Yi10

    子任务 3 (21 分) 1 ≤ N ≤ 1001N100

    A = 1A=1

    1 leq B leq N1BN

    0 leq Y_i leq 200Yi20

    子任务 4 (25 分) 1 leq N leq 1001N100

    1 leq A leq B leq N1ABN

    0 leq Y_i leq 10000000000Yi1000000000

    子任务 5 (29 分) 1 leq N leq 20001N2000

    A = 1A=1

    1 leq B leq N1BN

    0 leq Y_i leq 10000000000Yi1000000000

    因为是最小优美度,所以贪心很显然,高位尽可能为0

    n<=100时

    首先从高到低枚举每一位

    f[i][j]表示前i个,分了j组,这一位是否能为0

    O(n^3)的DP

    由于可能存在低位为0的方案与高位为0冲突

    我们设一个变量now,第i位为1表示当前位必须为0

    首先now该位变成1

    转移条件(sum[i]-sum[j-1])&now=0

    如果f[n][A~B]没有1,那么now该位改为0

    当n<=1000时,因为A=1

    换一种DP方式,f[i]表示前i位是否存在该位为0的方案,F[i]表示最小的分组数

    看是否有F[n]<=B

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 typedef long long lol;
     8 int f[101][101],A,B,n,flag;
     9 lol pw[101],sum[2001],a[2001],now,ans,F[2001],Min[2001];
    10 void dp1()
    11 {int i,j,k,l;
    12   int Log=log2(sum[n]);
    13   pw[0]=1;
    14   for (i=1;i<=Log;i++)
    15     pw[i]=pw[i-1]*2;
    16   for (i=Log;i>=0;i--)
    17     {
    18       now|=pw[i];
    19       memset(f,0,sizeof(f));
    20       f[0][0]=1;
    21       for (j=1;j<=n;j++)
    22       {
    23         for (l=0;l<=j-1;l++)
    24           if (((sum[j]-sum[l])&now)==0)
    25             {
    26             for (k=1;k<=l+1&&k<=j;k++)
    27             f[j][k]|=f[l][k-1];
    28             }
    29       }
    30       flag=0;
    31       for (j=A;j<=B;j++)
    32       {
    33         if (f[n][j]) {flag=1;break;}
    34       }
    35       if (!flag)
    36       now^=pw[i];
    37     }
    38   ans=0;
    39   for (i=0;i<=Log;i++)
    40     if ((now&pw[i])==0) ans+=pw[i];
    41   cout<<ans;
    42 }
    43 void dp2()
    44 {int i,j,k,l;
    45   int Log=log2(sum[n]);
    46   pw[0]=1;
    47   for (i=1;i<=Log;i++)
    48     pw[i]=pw[i-1]*2;
    49   for (i=Log;i>=0;i--)
    50     {
    51       now|=pw[i];
    52       memset(F,0,sizeof(F));
    53       memset(Min,127/2,sizeof(Min));
    54       F[0]=1;Min[0]=0;
    55       for (j=1;j<=n;j++)
    56       {
    57         for (k=0;k<=j-1;k++)
    58           if (((sum[j]-sum[k])&now)==0)
    59           {
    60             F[j]|=F[k];
    61             if (F[k])
    62             Min[j]=min(Min[j],Min[k]+1);
    63           }
    64       }
    65       if (!(F[n]&&Min[n]<=B))
    66       now^=pw[i];
    67     }
    68   ans=0;
    69   for (i=0;i<=Log;i++)
    70     if ((now&pw[i])==0) ans+=pw[i];
    71   cout<<ans;
    72 }
    73 int main()
    74 {int i;
    75   cin>>n>>A>>B;
    76   for (i=1;i<=n;i++)
    77     {
    78       scanf("%lld",&a[i]);
    79       sum[i]=sum[i-1]+a[i];
    80     }
    81   if (n<=100)
    82     dp1();
    83   else
    84     dp2();
    85 }
  • 相关阅读:
    winform最大化后不遮挡任务栏
    TabControl控件重绘
    EXT gridPanel 添加图片
    好记性不如烂笔头——double
    好记性不如烂笔头——datagridview相关
    datagridview合并相同单元格
    datagridview问题
    Linux折腾记
    TSC打印机使用教程终极版
    在线直播流测试地址
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8908965.html
Copyright © 2011-2022 走看看