#dp,Dilworth定理#洛谷 4934 礼物

题目传送门


分析

首先,可以放在一起当且仅当 \(\max\{a_i,a_j\} \& \min\{a_i,a_j\} \neq \min\{a_i,a_j\}\)

根据 Dilworth 定理可知最小链划分中链的数目等于最长反链的长度

所以设 \(dp[i]\) 表示以 \(i\) 为结尾的反链的最大长度,则 \(dp[i]=\max_{j| i}\{dp[j]\}+[a_k==i]\)

构造可以根据当前的 \(dp\) 值划分给各个箱子,因为最终答案为 \(dp[2^k-1]\)


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N=1050011;
int n,m,v[N],dp[N];
vector<int>K[N];
int iut(){
	int ans=0,f=1; char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans*f; 
}
void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
int main(){
	n=iut(),m=iut();
	for (int i=1;i<=n;++i) ++v[iut()];
	for (int i=0;i<(1<<m);++i){
		for (int j=i;j;j&=j-1) dp[i]=max(dp[i],dp[i^(-j&j)]);
		if (v[i]) K[++dp[i]].push_back(i);
	}
	putchar(49),putchar(10),print(dp[(1<<m)-1]);
	for (int i=1,len;i<=dp[(1<<m)-1];++i){
		putchar(10),print(len=K[i].size());
		for (int j=0;j<len;++j) putchar(32),print(K[i][j]);
	}
	return 0;
}
posted @ 2024-05-09 20:13  lemondinosaur  阅读(6)  评论(0编辑  收藏  举报