1. 程式人生 > >[數位DP]luogu P3646 [APIO2015]巴厘島的雕塑

[數位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

&n