B. Two Sets
题意:n个不相同的数p1~pn,把它们划分为两个集合。必须满足如果pi在集合0中,a-pi也在集合0中;如果pi在集合1中,b-pi也在集合1中。
思路:先排序,然后贪心从两边开始构造。两个指针l和r,指向未构造区间的左边和右边。如果pl和pr能放在一个集合中,就把它们放到一个集合。如果不行,就为pl找一个合适的(用二分查找),必须放在a和b中较小那个数的集合,找不到适合的数的话就是无解。因为pl和pr放不进max(a,b)那个集合,其他数就算放进去了,pr也是无解,所以只需要考虑min(a,b)那个集合。比赛的时候我跪在了n=1的情况,坑啊。。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctype.h>
using namespace std;
int num[100010];
int ha[100010];
int rnk[100010];
int cmp(int a,int b){
return num[a]<num[b];
}
int find(int x,int l,int r){
int mid;
while(1){
mid=(l+r)/2;
if(num[rnk[mid]]==x)return mid;
if(l==r)return -1;
if(num[rnk[mid+1]]==x)return mid+1;
if(l+1==r)return -1;
if(num[rnk[mid]]>x){
r=mid;
}else{
l=mid;
}
}
}
int main(){
int n,a,b;
while(cin>>n>>a>>b){
memset(ha,-1,sizeof(ha));
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
rnk[i]=i;
}
sort(rnk+1,rnk+n+1,cmp);
if(n==1){
if(num[1]*2==a){
cout<<"YES"<<endl;
cout<<0;
break;
}
if(num[1]*2==b){
cout<<"YES"<<endl;
cout<<1;
break;
}
cout<<"NO"<<endl;
break;
}
int l=1;
int r=n;
bool ok=1;
while(1){
bool brk=0;
while(ha[rnk[l]]!=-1){
if(l>=r){
brk=1;
break;
}
l++;
}
while(ha[rnk[r]]!=-1){
if(l>=r){
brk=1;
break;
}
r--;
}
if(brk)break;
if(num[rnk[l]]+num[rnk[r]]==a){
ha[rnk[l]]=ha[rnk[r]]=0;
l++; r--;
continue;
}
if(num[rnk[l]]+num[rnk[r]]==b){
ha[rnk[l]]=ha[rnk[r]]=1;
l++; r--;
continue;
}
//
int fl=find( min(a,b)-num[rnk[l]],l,r);
if( fl ==-1 || ha[rnk[fl]]!=-1 ){
ok=0;
break;
}
if( num[rnk[l]]+num[rnk[fl]]==a ){
ha[rnk[l]]=0;
ha[rnk[fl]]=0;
}
if( num[rnk[l]]+num[rnk[fl]]==b ){
ha[rnk[l]]=1;
ha[rnk[fl]]=1;
}
}
if(ok){
cout<<"YES"<<endl;
for(int i=1;i<=n;i++){
cout<<ha[i]<<" ";
}
}else{
cout<<"NO"<<endl;
}
}
return 0;
}