[UOJ 110][APIO 2015]Bali Sculptures(按位DP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qpswwww/article/details/46562403

题目链接

http://uoj.ac/problem/110

思路

此题如果直接用类似于NOIP乘积最大一题的那种DP做法的话,是错误的,因为此题有后效性。

可以考虑拆位来做,先尽量让答案的高位为0,在答案高位尽量小的前提下,再争取让答案的低位为0。

对于前4个subtask,由于A>=1,因此直接用DP求每一位的最少分组的话是不对的。可以采取O(n3logY)的做法,从最高位向最低位枚举第bit位,用f[i][j]表示在满足答案的第bit+1,bit+2...位不变(最优)的情况下,第bit位能否取0。若存在某个f[n][k](k[A,B])成立的话,答案的这一位可以为0,否则只能取1。

最后一个subtask这样做会TLE。但是A=1,可以采取O(n2logY)的做法,从最高位向最低位枚举第bit位,用f[i]表示在满足答案的第bit+1,bit+2...位不变(最优)的情况下,第bit位取0最少需要分成几组。若f[n]B的话,答案的这一位可以为0,否则只能取1。

注意:由于或运算的特殊性,因此答案的第bit+1,bit+2...位或上某段区间之和的第bit+1,bit+2...位依然不变的话,表明这段区间不会影响最终答案的第bit+1,bit+2...位(这段区间的某一位为0或1,而答案为1,或运算后答案这一位还为1,但是这段区间的某一位为1,而答案为0,或运算后答案这一位为1,无论其他段的区间取值如何,都会对最终或出来的答案产生影响)

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define INF 0x3f3f3f3f

using namespace std;

typedef long long int LL;

LL sum[2100],ans=0;
int n,A,B,bitlen;

namespace AEqualToOne
{
    const int MAXN=2100;
    int f[MAXN]; //f[i]=dp到第bit位时,前i个数要满足bitlen~bit+1位和答案相符,且第bit位为0,至少要分成几组
    void solve()
    {
        for(int bit=bitlen;bit>=0;bit--)
        {
            memset(f,INF,sizeof(f));
            f[0]=0;
            for(int i=1;i<=n;i++)
                for(int j=0;j<i;j++)
                    if(f[j]<B)
                    {
                        LL tmp=sum[i]-sum[j];
                        if((((tmp>>(LL)(bit+1)))|ans)==ans&&(tmp&(1LL<<(LL)bit))==0) f[i]=min(f[i],f[j]+1);
                    }
            ans<<=1;
            if(f[n]>B) ans++;
        }
    }
}

namespace ANeqOne
{
    const int MAXN=110;
    int f[MAXN][MAXN]; //假设当前dp到了第x位,f[i][j]=在满足答案的第x+1位不变(最优)的情况下,第x位能否取0
    void solve()
    {
        f[0][0]=1;
        for(int bit=bitlen;bit>=0;bit--)
        {
            memset(f,0,sizeof(f));
            f[0][0]=1;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    for(int k=0;k<i;k++) //f[k][j-1]转移到f[i][j]
                    {
                        if(f[k][j-1])
                        {
                            LL tmp=sum[i]-sum[k];
                            if((((tmp>>(LL)(bit+1)))|ans)==ans&&(tmp&(1LL<<(LL)bit))==0) f[i][j]=1;
                        }
                    }
            bool flag=false; //flag=true表示第bit位可以取0
            for(int i=A;i<=B;i++)
                if(f[n][i])
                {
                    flag=true;
                    break;
                }
            ans<<=1;
            if(!flag) ans++;
        }
    }
}

int main()
{
    scanf("%d%d%d",&n,&A,&B);
    for(int i=1;i<=n;i++)
    {
        LL x;
        scanf("%I64d",&x);
        sum[i]=sum[i-1]+x;
    }
    for(;(1LL<<(LL)bitlen)<sum[n];bitlen++);
    bitlen--;
    if(A==1)
    {
        using namespace AEqualToOne;
        solve();
    }
    else
    {
        using namespace ANeqOne;
        solve();
    }
    printf("%lld\n",ans);
    return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页