1. 程式人生 > >P4934 禮物---------------拓撲圖,優化建邊。

P4934 禮物---------------拓撲圖,優化建邊。

題目描述

__stdcall決定給你nn個禮物,每個禮物有一個魔力值a_iai。這些禮物的魔力值都是獨一無二的,兩兩互不相同。這些禮物都有著神奇的魔力,如果兩個禮物i, ji,j的魔力值滿足 a_i \& a_j \ge min(a_i, a_j)ai&ajmin(ai,aj) ,那麼這兩個禮物的魔力將會相互抵消,因此它們不能放在一個箱子裡。這裡的\&&是按位與運算子,如果你對這一運算不夠了解,請參考:https://baike.baidu.com/item/%E6%8C%89%E4%BD%8D%E4%B8%8E/9601818?fr=aladdin

作為發禮物苦力的ljt12138的箱子並不多,不過幸運的是,每個箱子都足夠大。現在他請求你幫助他合理分配,用盡可能少的箱子裝下所有禮物。換言之,使得每個禮物都被恰好裝入一個箱子中,且同一個箱子中的禮物魔力不會相互抵消。如果有多種合法的方案,你只需要給出任意一種。

ljt12138十分善良,如果你只能求出所需要的箱子數,也可以獲得該測試點60%的分數,關於這一點,請參考下面的提示與說明。

輸入輸出格式

輸入格式:

 

  • 第一行兩個數 nn和kk,nn為禮物總數,kk為一個引數,方便你進行計算。
  • 第二行 nn個兩兩不同的數a_iai,滿足0\le a_i < 2^k0ai<2k,表示禮物的魔力值。

 

輸出格式:

 

  • 第一行輸出一個數。如果你不希望輸出方案,請輸出0;如果你希望輸出方案,請輸出1。如果你在這一行輸出了不符合要求的資訊,將被判為 WAWA。
  • 第二行一個數 mm,表示你將禮物裝到了mm個箱子裡。
  • 如果你在第一行輸出了 11,接下來mm行,每行表示一個箱子:首先一個數s_isi,表示當前箱子中禮物的個數;接下來s_isi個數,表示當前子集。

 

輸入輸出樣例

輸入樣例#1:
5 3
0 4 7 1 6 
輸出樣例#1:
1
4
1 0
2 1 4
1 6
1 7 

說明

附加樣例:

你可以在 https://pan.baidu.com/s/1A8_ZA4yXXi5y6771x9JKUw 下載附加樣例。

關於輸出方案:

  • 如果你在第一行輸出了 00,而正確回答了最小所需的箱子數,將獲得測試點60%的分數。
  • 如果你在第一行輸出了 11,正確回答了最小所需的箱子數,但沒有給出正確的方案,也將獲得該測試點60%的分數。
  • 如果你沒有正確回答最小所需的箱子數,將不會獲得該測試點的分數。
  • 請選手注意,如果你未按照上述格式輸出答案,將無法獲得任何分數。

資料n, kn,k的關係由下面的表格給出:

資料編號 nn kk
11 55 33
22 66 33
33 77 1010
44 88 1010
55 1616 77
66 1717 88
77 1717 99
88 1717 2020
99 20002000 1717
1010 25002500 1818
1111 30003000 1919
1212 30003000 2020
1313 2500025000 1515
1414 2500025000 1515
1515 5000050000 1616
1616 5000050000 1616
1717 250000250000 1818
1818 500000500000 1919
1919 10000001000000 2020
2020 10000001000000 2020

 


 

一句話題解:偏序集最小反鏈覆蓋等於最長鏈,優化建圖。

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int siz=2000050;
 4 int n,m,a[siz],t;
 5 int dis[siz];
 6 bool vis[siz];
 7 int head[siz],nex[siz],tot[siz];
 8 vector <int > s[20];
 9 void add(int x,int y)
10 {
11     ++tot[x];
12     nex[y]=head[x];
13     head[x]=y;
14 }
15 int main()
16 {
17     scanf("%d%d",&n,&m);
18     t=(1<<m)-1;
19     for(int i=0;i<n;++i)
20     {
21         scanf("%d",&a[i]);
22         vis[a[i]]=true;
23     }
24     for(int i=t;i>=0;--i)
25     {
26         if(vis[i])
27             ++dis[i];
28         for(int j=1;j<t;j<<=1)
29             if(i&j)
30                 dis[i^j]=max(dis[i^j],dis[i]);
31     }
32     for(int i=0;i<=t;++i)
33         if(vis[i])
34             s[dis[i]].push_back(i);
35     printf("%d\n%d",1,dis[0]);
36     for(int i=dis[0];i>=1;--i)
37     {
38         int tmp=s[i].size();
39         printf("\n%d",tmp);
40         for(int j=0;j<tmp;++j)
41             printf(" %d",s[i][j]);
42             
43     }
44     return 0;
45 }
程式碼