• [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 }
  • 相关阅读:
    SuperMap房产测绘成果管理平台
    SuperMap产权登记管理平台
    Android adb shell am 的用法(1)
    由浅入深谈Perl中的排序
    Android 内存监测和分析工具
    Android 网络通信
    adb server is out of date. killing...
    引导页使用ViewPager遇到OutofMemoryError的解决方案
    adb logcat 详解
    How to send mail by java mail in Android uiautomator testing?
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8908965.html
Copyright © 2020-2023  润新知