题解 JZOJ 1162.【普及组模拟赛】最大杂置(set)

题目描述:

S S n n 个元素的集合,则S有 2 n 1 2^{n-1} 个子集(除去空集)。现在要你从这 2 n 1 2^{n-1} 个子集中选出最多的子集,使这些子集能构成一个杂置。
杂置是指任意两个集合没有包含或被包含的关系。例如对于有3个元素的集合 { a , b , c } \{a,b,c\}
{ a , b } { a , c } { b , c } \{a,b\},\{a,c\},\{b,c\} 可以构成一个杂置,而 { a } , { b } , { a , b } \{a\},\{b\},\{a,b\} 则不能构成一个杂置。

输入:

第一行一个 t t 表示包括t组数据,接下来 t t 行每行一个 n n

输出:

对于每组数据输出最大杂置包含的集合数。结果模12345678。

推导过程:

首先我们明确,选取构成杂置的子集合元素个数相等,则可以保证不被互相包含。
假设我们选取的子集合元素个数为 k k ,那么就有 C n k C_n^k 种选法。
则:
a n s = max 1 i n C n k ans=\max_{1\le i\le n}C_n^k
考虑到数列 C n k C_n^k 具有单峰性,即最大值唯一。
直接求解不支持模数,所以转化成帕斯卡三角形求解:
C n k = ( n k ) C_n^k={n\choose k}
帕斯卡三角形具有以下性质:
( n k ) = ( n 1 k 1 ) + ( n 1 k ) {n \choose k}={n-1\choose k-1}+{n-1\choose k}
运用加法原理可证,即分为在前 n 1 n-1 个数当中选 k 1 k-1 k k 个数。
又有:
( n k ) = ( n n k ) = n ! k ! ( n k ) ! {n\choose k}={n\choose n-k}=\frac{n!}{k!(n-k)!}
根据不等式基本性质,可知 ( n k ) {n\choose k} 的单峰值在 k = n 2 k=\frac{n}{2} 时。
代码如下:

#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;
}

文献资料部分参考于《组合数学》第五章。

猜你喜欢

转载自blog.csdn.net/alpha202/article/details/89059034