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