巴厘岛的一条主干道上共有
N
N
N 座雕塑,依次编号为
1
1
1 到
N
N
N。雕塑
i
i
i 的年龄为
Y
i
Y_i
Yi。
政府想把这些雕塑分成恰好
X
X
X 组,要求
A
≤
X
≤
B
A≤X≤B
A≤X≤B。每组不能为空,且每组雕塑的编号必须连续。每个雕塑必须属于某一组。
分组方案需要考虑美观程度。计算方法如下:分别计算每组雕塑的年龄之和,然后将每一组的结果按位取或,就得到了该分组方案的美观值。
求最小的美观值。
前四档:
N
<
=
100
,
1
<
=
A
,
B
<
=
N
,
Y
i
<
=
1
0
9
N<=100,1<=A,B<=N,Y_i<=10^9
N<=100,1<=A,B<=N,Yi<=109
最后一档:
N
<
=
2000
,
A
=
1
,
B
<
=
N
,
Y
i
<
=
1
0
9
N<=2000,A=1,B<=N,Y_i<=10^9
N<=2000,A=1,B<=N,Yi<=109
这数据范围很显然要分段了。。。
先考虑前四档怎么做,直接DP肯定不行,贪心逐位确定?
考虑一位能不能填0,那么要求分出来的组之和这一位都不能有1,那么前面的位怎么办?
发现只要满足前面的位不出现多余的1即可,因为我们贪心已经使前面最小了。
那么一个
N
3
log
(
N
∗
Y
i
)
N^3\log{(N*Y_i)}
N3log(N∗Yi)的DP就做完了。
考虑第五档部分分怎么做,发现只要让分的组尽量少,那么状态改设
f
i
f_i
fi表示分到
i
i
i且合法的最小组数,像上面一样转移即可。复杂度
O
(
N
2
∗
log
(
N
∗
Y
i
)
)
O(N^2*\log{(N*Y_i)})
O(N2∗log(N∗Yi))
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 1e2 + 5;
const int M = 2e3 + 5;
typedef long long ll;
int a[M],f[N][N],g[M];
int n,A,B;
int main()
{
scanf("%d%d%d",&n,&A,&B);
for (int i = 1 ; i <= n ; ++i) scanf("%d",&a[i]);
if (n <= 100)
{
ll ret = 0;
for (int i = 40 ; ~i ; --i)
{
memset(f,0,sizeof(f));
f[0][0] = 1;
for (int j = 1 ; j <= n ; ++j)
{
ll su = 0;
for (int k = j ; k ; --k)
{
su += a[k];
for (int l = 0 ; l < j ; ++l)
if (f[k - 1][l] && !(su & (1ll << i)) && (((su >> i) << i) | ret) == ret) f[j][l + 1] = 1;
}
}
bool flag = 0;
for (int j = A ; j <= B ; ++j)
if (f[n][j]) { flag = 1; break; }
if (!flag) ret |= 1ll << i;
}
printf("%lld\n",ret);
}else
{
ll ret = 0;
for (int i = 40 ; ~i ; --i)
{
memset(g,0x3f,sizeof(g));
g[0] = 0;
for (int j = 1 ; j <= n ; ++j)
{
ll su = 0;
for (int k = j ; k ; --k)
{
su += a[k];
if (!(su & (1ll << i)) && (((su >> i) << i) | ret) == ret) g[j] = min(g[j],g[k - 1] + 1);
}
}
if (g[n] > B) ret |= 1ll << i;
}
printf("%lld\n",ret);
}
return 0;
}