CodeForces - 468B Two Sets(并查集+思维)
題目鏈接:點擊查看
題目大意:現在給出兩個集合A和B,再給出兩個數a和b,現在規定在集合A中的數x必須滿足x和a-x同時在集合a中,而在集合B中的數x也同樣需要滿足x和b-x同時在集合B中,現在給出一系列數,問能否將所有的數都分配到兩個集合中去
題目分析:這個題因為放在了二分圖的專題里,所以一開始想盡了一切辦法想將這個題目往匈牙利上靠攏,但最終沒辦法將模型抽象出來,看了題解后才知道是個簡單并查集的題目,這里分析一下吧,對于任意一個x,無非只有四種情況:
因為給出的n個數兩兩都是不同的,并且都是正整數,所以我們可以在一開始的時候就剪一下枝,如果數列中的最大值大于等于a或b中的最大值顯然是輸出NO的,因為這個時候無論是a還是b,減去這個最大值一定是一個負數,肯定找不到與其對應的一個正整數,這種情況可以歸類為上面所述的第一種情況
我們維護1~n為數列,然后0為集合A,n+1為集合B,在輸入的時候就用map維護每個數的下標,最后遍歷一遍,按照上述的2-4規則用并查集維護一下下標,將x和a-x建邊或x和b-x建邊,最后判斷即可
該怎么判斷呢?因為如果滿足了第一種情況,也就是a-x和b-x在數列中都不存在的話,那么這個數肯定被else判斷到了兩個集合中去了,也就是將點0和點n+1建了一條邊,第二種情況和第三種情況都會根據巧妙的邏輯將其與相應的集合建邊,不重不漏,最后如果都存在的話,則只會先將這三個點:x,a-x,b-x三點建邊,等到后續判斷a-x的時候,以及b-x的時候,再利用else的邏輯將其與相應集合建邊
不得不佩服這個題的思維邏輯
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;int val[N];unordered_map<int,int>pos;int f[N];int find(int x) {return x==f[x]?x:f[x]=find(f[x]); }void merge(int x,int y) {int xx=find(x);int yy=find(y);f[xx]=yy; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);int n,a,b;scanf("%d%d%d",&n,&a,&b);int mmax=0;for(int i=1;i<=n;i++){scanf("%d",val+i);pos[val[i]]=i;mmax=max(mmax,val[i]);}if(mmax>=max(a,b))return 0*printf("NO\n");for(int i=0;i<=n+1;i++)f[i]=i;for(int i=1;i<=n;i++){if(pos[a-val[i]])//如果x與a-x有對應,就建邊merge(i,pos[a-val[i]]);else//否則將x加入到集合B中去merge(i,n+1);if(pos[b-val[i]])//如果x與b-x有對應,就建邊merge(i,pos[b-val[i]]);else//否則將x加入到集合A中去merge(i,0);}int A=find(0);int B=find(n+1);if(A==B)printf("NO\n");else{printf("YES\n");for(int i=1;i<=n;i++){if(find(i)==A)printf("0");elseprintf("1");if(i!=n)putchar(' ');elseputchar('\n');}}return 0; }?
總結
以上是生活随笔為你收集整理的CodeForces - 468B Two Sets(并查集+思维)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU - 3804 Query on
- 下一篇: HDU - 1528 Card Game