题目链接
思路
此题如果直接用类似于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;
}