BZOJ 4069 [Apio2015]巴厘岛的雕塑 ——贪心
自己首先想了一种方法$f(i)$表示前$i$个最小值为多少。
然而发现位运算并不满足局部最优性。
然后我们可以从高到低贪心的判断,使得每一组的和在一个特定的范围之内。
还要特判最后一个Subtask,
想了想不用特判的办法,觉得bitset压不过去,就没写。
#include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define ll long long #define llinf 10000000000000000LL #define mp make_pair int n,a,b; ll y[2005],ans=llinf,upper,lower=0; bool f[2][2005]; int g[2005]; bool test() { int now=0,pre=1; memset(f[now],false,sizeof f[now]); f[0][0]=true; F(j,0,b-1) { now^=1; pre^=1; memset(f[now],false,sizeof f[now]); F(i,0,n-1) if (f[pre][i]) F(k,i+1,n) if ((y[k]-y[i]|lower)<=upper) { f[now][k]=true; if (k==n&&j+1>=a) return true; } } return false; } bool test2() { memset(g,0x3f,sizeof g); g[0]=0;F(i,1,n) F(j,0,i-1) if ((y[i]-y[j]|lower)<=upper) g[i]=min(g[j]+1,g[i]); return g[n]<=b; } int main() { scanf("%d%d%d",&n,&a,&b); F(i,1,n) scanf("%lld",&y[i]); F(i,1,n) y[i]+=y[i-1]; D(i,40,0) { memset(f,false,sizeof f); upper=((1LL<<i)-1);upper+=lower; if ((n<=500&&!test())||(n>500&&!test2())) lower+=1LL<<i; } printf("%lld\n",lower); }