[数位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()); }
在日渐沉没的世界里,我发现了你。