题目描述:一堆公司,每个公司有个子公司,公司编号为i,子公司编号为-i。每个公司的人数比子公司多,两个公司,如果一个的人数比另一个多,那么他的子公司的人数也多。
然后求一个构造,使得编号比i这个公司大的公司中,人数比他多的是c[i],同时编号比他的子公司大的子公司中,人数比他的子公司多的也是c[i]
解法: 以下来自官方题解
1.一开始开2个队列a,b。a为答案队列,b为临时队列
2.找出当最小的C值为C[k](相同时取k最小的)
a)C[k]=0:将k加入a,-k加入b。在C序列中删除元素C[k],并将C[1]到C[k-1]减一。
b)C[k]>0:将b队首的元素p取出加入a,并将C[-p+1]到c[n]减一。
重复做直到所有元素进入a或者b
3.将b接在a后面,倒序就是答案序列
无解有两种情况:
1.C中出现了负数。
2.出现2b情况时b为空
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; #define prt(k) cout<<#k" = "<<k<<endl; const int N = 100010<<2; const int inf = 0x3f3f3f3f; int c[N]; struct data { int v, id; data() {} data(int a, int b) { v=a, id=b; } }; data tree[N]; int add[N]; int ans[N]; int n,m,cnt; data Min(data x, data y) { if(x.v<y.v || (x.v==y.v&&x.id<y.id)) return x; else return y; } void pushup(int o) { tree[o]=Min(tree[o*2],tree[o*2+1]); } void build(int l, int r, int o) { add[o]=0; if(l==r) { tree[o]=data(c[l], l); return ; } int m=(l+r)/2; build(l,m,o*2); build(m+1,r,o*2+1); pushup(o); } void pushdown(int l, int r, int o) { if(l==r) return; if(add[o]) { add[o*2]+=add[o]; add[o*2+1]+=add[o]; tree[o*2].v+=add[o]; tree[o*2+1].v+=add[o]; add[o]=0; } } void update(int L,int R,int v, int l,int r,int o) { if(L<=l&&r<=R) { if(v==inf) { tree[o].v = inf; add[o]=0; return; } tree[o].v+=v; add[o]+=v; return; } pushdown(l,r,o); int m=(l+r)/2; if(L<=m) update(L,R,v, l,m,o*2); if(m<R) update(L,R,v, m+1,r,o*2+1); pushup(o); } data query(int L,int R, int l,int r,int o) { if(L<=l && r<=R) return tree[o]; pushdown(l,r,o); int m=(l+r)/2; data ans=data(inf,0); if(L<=m) ans=Min(ans,query(L,R, l,m,o*2)); if(m<R) ans=Min(ans,query(L,R, m+1,R,o*2+1)); return ans; } #include<deque> #include<queue> int main() { while(scanf("%d",&n)==1) { if(n==0) break; bool flag = 1; for(int i=1;i <=n;i++) { scanf("%d",c+i); if(c[i]<0) { puts("Impossible"); flag = 0; } } if(!flag) continue; build(1,n,1); queue<int> a,b; cnt=n; int t=0; while(cnt) { data u = query(1,n, 1,n,1); int k=u.id; if(u.v==inf) break; if(u.v==0 ) { ans[t++] = k; b.push(-k); update(k,k,inf, 1,n,1); if(k>1) update(1,k-1,-1, 1,n,1); cnt--; } else if(u.v > 0) { if(b.empty()) { flag = 0; break; } int p=b.front(); ans[t++]=p; b.pop(); if(-p+1<=n&&-p+1>=1) update(-p+1,n,-1, 1,n,1); } } if(flag==false) { puts("Impossible"); continue; } while(!b.empty()) { ans[t++]=b.front(); b.pop(); } n = 2*n; for(int i=n-1;i>0;i--) printf("%d ",ans[i]); printf("%d \n",ans[0]); } }