[数位DP]luogu P3646 [APIO2015]巴厘岛的雕塑

题面

https://www.luogu.com.cn/problem/P3646

分析

直接得到最终优美度是显然不可做的,注意到二进制位数并不多,考虑从高位逐位计算

设方程 f[i][j] 表示分组完第 i 个数,用了 j 组,最终优美度能否为 0

目前枚举到第 k 位,那么 k+1~maxbit 的位上已经确定了 0 1 了

我们考虑把当前这位钦定为 0 ,高位符合已确定的值,则低位可以任意

这时候就可以用简单的 O(n^3) DP完成转移,如果存在 $f[n][i] (i\in [A,B])$ 为真,则该位可以为 0 ,否则为 1

转移方程: $f[i][j]|=f[k][j-1]|(sum_{k+1~i}满足当前位为0,高位符合已确定值)$

发现对于子任务 5 无法通过,再观察性质:A=1

则不需要判断是否存在$f[n][i] (i\in [a,b])$ 为真,只需要设 g[i] 表示选择到第 i 个满足限制的最小分组数,有 $g[n]\leq B$ 该位即可为 0

分任务通过

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=2e3+10;
int n,a,b,bit;
ll y[N];
int f[N][N];

ll DP1() {
    ll ans=0;
    for (ll i=1ll<<bit;i;i>>=1) {
        bool zerable=0;memset(f,0,sizeof f);f[0][0]=1;
        for (int j=1;j<=n;j++)
            for (int k=1;k<=min(j,b);k++)
                for (int l=j-1;l>=k-1;l--) {
                    f[j][k]=(f[l][k-1]&&((ans|i-1ll)|y[j]-y[l])==(ans|i-1ll));
                    if (f[j][k]) break;
                }
        for (int j=a;j<=b;j++) if (f[n][j]) {zerable=1;break;}
        if (!zerable) ans|=i;
    }
    return ans;
}

ll DP2() {
    ll ans=0;
    for (ll i=1ll<<bit;i;i>>=1) {
        bool zerable=0;
        f[0][0]=0;for (int j=1;j<=n;j++) f[j][0]=n+1;
        for (int j=1;j<=n;j++)
            for (int l=j-1;l>=0;l--)
                if (((ans|i-1ll)|y[j]-y[l])==(ans|i-1ll)) f[j][0]=min(f[j][0],f[l][0]+1);
        if (f[n][0]>b) ans|=i;
    }
    return ans;
}

int main() {
    scanf("%d%d%d",&n,&a,&b);
    for (int i=1;i<=n;i++) scanf("%lld",&y[i]),y[i]+=y[i-1];bit=log2(y[n])+1;
    printf("%lld\n",(a!=1)?DP1():DP2());
}
View Code

 

posted @ 2021-03-25 19:10  Vagari  阅读(35)  评论(0编辑  收藏  举报