题目:分隔相同整数
链接:http://hihocoder.com/problemset/problem/1356
题意:给一个数组,要求重新排列,使得相同的数不在一起,同时字典序最小(先判断第一个整数,再判断第二个,...),无解就输出-1,n范围10万,每个数范围10亿。
思路:
好题,记得以前刚开始搞acm的时候见过一道类似的,不过他只要求判断有无解,这题还要输出重排后的序列。可惜比赛的时候没做出来,思路是想到了,问题是时间不够,脑袋晕乎乎的写不下去。
首先,无解的情况:记maxt为数组中出现次数最多的数的出现次数,如果满足maxt>(n+1)/2肯定无解,这点挺好想的。
现在我们再来解决重排的问题:
如果maxt>n-maxt,那么我们肯定要输出maxt对应的数,否则我们就可以输出最小的,有剩余的,不和前一个相同的数,输出一个后对应数的数量就要相应减少了,然后n次循环就可以解决了。
有了大致思路,我们可以先对原数组排序,然后用num数组记录个数去重压缩(比如2 2 3 3 3 压缩成2 3,num[1]=2,num[2]=3)。因为要重复很多次找出数组中出现次数最多的数,我们可以用线段树保存数值和次数,然后维护最大次数(次数和值)(这点算是线段树最简单的应用了)。然后按上一段讲的规则n次循环就可以了。
AC代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 #define N 100010 6 int a[N]; 7 int num[N]; 8 int ao,n; 9 10 struct Node 11 { 12 int val; 13 int num; 14 int l,r; 15 int mid() 16 { 17 return (l+r)/2; 18 } 19 }; 20 Node v[400040]; 21 void build(int l,int r,int rt) 22 { 23 v[rt].l=l; 24 v[rt].r=r; 25 if(l==r) 26 { 27 v[rt].val=l; 28 v[rt].num=num[l]; 29 return ; 30 } 31 build(l,v[rt].mid(),rt<<1); 32 build(v[rt].mid()+1,r,rt<<1|1); 33 if(v[rt<<1].num>v[rt<<1|1].num) 34 { 35 v[rt].num=v[rt<<1].num; 36 v[rt].val=v[rt<<1].val; 37 } 38 else 39 { 40 v[rt].num=v[rt<<1|1].num; 41 v[rt].val=v[rt<<1|1].val; 42 } 43 } 44 int min(int a,int b) 45 { 46 return a<b?a:b; 47 } 48 void update(int x,int rt) 49 { 50 if(v[rt].l==v[rt].r) 51 { 52 v[rt].num--; 53 return ; 54 } 55 if(x<=v[rt].mid()) 56 update(x,rt<<1); 57 else update(x,rt<<1|1); 58 if(v[rt<<1].num>v[rt<<1|1].num) 59 { 60 v[rt].num=v[rt<<1].num; 61 v[rt].val=v[rt<<1].val; 62 } 63 else 64 { 65 v[rt].num=v[rt<<1|1].num; 66 v[rt].val=v[rt<<1|1].val; 67 } 68 } 69 70 void solve() 71 { 72 if(v[1].num>(n+1)/2) 73 { 74 printf("-1 "); 75 return ; 76 } 77 int ln=1,pre=-1; 78 while(n) 79 { 80 if(n-v[1].num<v[1].num) 81 { 82 pre=a[v[1].val]; 83 printf("%d",pre); 84 num[v[1].val]--; 85 update(v[1].val,1); 86 } 87 else 88 { 89 while(!num[ln]) ln++; 90 int tl; 91 if(pre==a[ln]) tl=ln+1; 92 else tl=ln; 93 while(!num[tl]) tl++; 94 printf("%d",a[tl]); 95 pre=a[tl]; 96 update(tl,1); 97 num[tl]--; 98 } 99 n--; 100 if(n!=0) printf(" "); 101 } 102 printf(" "); 103 } 104 105 int main() 106 { 107 while(scanf("%d",&n)!=EOF) 108 { 109 for(int i=1;i<=n;i++) 110 { 111 scanf("%d",&a[i]); 112 } 113 sort(a+1,a+1+n); 114 ao=1; 115 num[ao]=1; 116 for(int i=2;i<=n;i++) 117 { 118 if(a[i]==a[i-1]) 119 { 120 num[ao]++; 121 } 122 else 123 { 124 ao++; 125 a[ao]=a[i]; 126 num[ao]=1; 127 } 128 } 129 build(1,ao,1); 130 solve(); 131 } 132 return 0; 133 }