链接:https://vjudge.net/contest/386991#problem/C
题意:给出2指数级倍数的倒数
让我们把这些数分为两个堆,看看能不能分别分出两个大于等于二分之一的堆
思路:用优先队列+并查集的方式
优先队列从大到小排序,然后每次取最大的两个数进行操作,如果两个数不同,则剔除最大的那个数,继续循环
如果相同,就合并,然后用并查集把这两个数的下标归到同一个区间
然后再把合并后的数放到优先队列里,新的数沿用合并数的下标,然后再操作即可。
直到遇到了1,或者队列大小小于2
但是有一个细节问题:假如一开始就有两个1的话,我们就直接另类讨论即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 int f[maxn]; 5 int a[maxn]; 6 struct node 7 { 8 int val; 9 int index; 10 friend bool operator <(const node &a,const node &b){ 11 return a.val<b.val; 12 } 13 }; 14 priority_queue<node>Q; 15 int getf(int u) 16 { 17 if(u==f[u]) return u; 18 f[u]=getf(f[u]); 19 return f[u]; 20 } 21 void Union(int u,int v) 22 { 23 if(u>v) swap(u,v); 24 int t1=getf(u); 25 int t2=getf(v); 26 if(t1!=t2){ 27 f[t2]=t1; 28 } 29 } 30 int main() 31 { 32 int T; 33 scanf("%d",&T); 34 int Case=0; 35 while(T--){ 36 int n; 37 scanf("%d",&n); 38 //init 39 for(int i=1;i<=n;i++) f[i]=i; 40 while(!Q.empty()) Q.pop(); 41 //init 42 node tmp; 43 int sum=0; 44 int base=0; 45 for(int i=1;i<=n;i++){ 46 scanf("%d",&tmp.val); 47 tmp.index=i; 48 if(tmp.val==1){ 49 sum++; 50 base=i; 51 } 52 Q.push(tmp); 53 } 54 if(sum>=2){ 55 printf("Case %d: YES\n",++Case); 56 int flag=0; 57 for(int i=1;i<=n;i++){ 58 if(i==base){ 59 printf("1"); 60 } 61 else printf("0"); 62 } 63 printf("\n"); 64 continue; 65 } 66 node a,b; 67 while(Q.size()>=2){ 68 a=Q.top(); 69 if(a.val==1){ 70 break; 71 } 72 Q.pop(); 73 b=Q.top(); 74 if(a.val==b.val){ 75 Union(a.index,b.index); 76 Q.pop(); 77 a.val-=1; 78 Q.push(a); 79 } 80 } 81 a=Q.top(); 82 if(Q.size()>=2&&a.val==1){ 83 printf("Case %d: YES\n",++Case); 84 int flag=getf(a.index); 85 for(int i=1;i<=n;i++){ 86 if(flag==getf(i)){ 87 printf("1"); 88 } 89 else printf("0"); 90 } 91 printf("\n"); 92 } 93 else{ 94 printf("Case %d: NO\n",++Case); 95 } 96 } 97 return 0; 98 }