题目描述:
令
为
个元素的集合,则S有
个子集(除去空集)。现在要你从这
个子集中选出最多的子集,使这些子集能构成一个杂置。
杂置是指任意两个集合没有包含或被包含的关系。例如对于有3个元素的集合
。
可以构成一个杂置,而
则不能构成一个杂置。
输入:
第一行一个 表示包括t组数据,接下来 行每行一个 。
输出:
对于每组数据输出最大杂置包含的集合数。结果模12345678。
推导过程:
首先我们明确,选取构成杂置的子集合元素个数相等,则可以保证不被互相包含。
假设我们选取的子集合元素个数为
,那么就有
种选法。
则:
考虑到数列
具有单峰性,即最大值唯一。
直接求解不支持模数,所以转化成帕斯卡三角形求解:
帕斯卡三角形具有以下性质:
运用加法原理可证,即分为在前
个数当中选
或
个数。
又有:
根据不等式基本性质,可知
的单峰值在
时。
代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1001;
int n, l, F[N][N][3], A[N];
int main()
{
freopen("ontherun.in", "r", stdin);
freopen("ontherun.out", "w", stdout);
scanf("%d %d", &n, &l);
for(int i = 1; i <= n; i++)
scanf("%d", &A[i]);
sort(A + 1, A + 1 + n);
for(int i = 1; i <= n; i++) {
F[i][i][1] = abs(A[i] - l) * n;
F[i][i][2] = abs(A[i] - l) * n;
}
for(int i = n; i >= 1; i--) {
for(int j = i + 1; j <= n; j++) {
F[i][j][1] = min(F[i + 1][j][1] + (n + i - j) * (A[i + 1] - A[i]), F[i + 1][j][2] + (n + i - j) * (A[j] - A[i]));
F[i][j][2] = min(F[i][j - 1][2] + (n + i - j) * (A[j] - A[j - 1]), F[i][j - 1][1] + (n + i - j) * (A[j] - A[i]));
}
}
printf("%d\n", min(F[1][n][1], F[1][n][2]));
return 0;
}
文献资料部分参考于《组合数学》第五章。