直接贪心(每次选最小)的话显然不对...样例都过不了... 选两个办公楼的时候,显然不能跨越另一个楼,这样不优... 于是 先把原数列处理成n-1个的数(每一个办公楼和上一个的距离),存在a[]中 题目就是 要求选出K个不相邻的数,使得选出的数的和最小
依然考虑贪心,每次选最小的 但是若a[]是2 1 2 6,要选K=2个,先选了1,然后会发现两个2都没法选,只好选6,这样就尴尬了... 1选了就选了吧,我们考虑补救措施... 就是选1的时候,在堆里删掉两个2,然后在堆中插入2+2-1 相当于 我们以后可以取到那两个2,而且2+2-1可以表示选了两个数,因为刚才选了1,所以在这里-1
还有个边界问题...比如取了第一个数或最后一个数,那么把a[0]和a[n]赋成极大值呗...
因为边界的数 的两侧 只有一个有效的数,无法补救了(补救的时候需要俩数...),赋成极大值那么以后都无法取到
那就要存储 一个数的前一个数是多少,后一个数是多少(方便删除)
7 2 1 2 6 8 取1,删掉俩2,然后新开一个链表空间a[++n],存储2+2-1,用这个链表空间取代2 1 2
新的链表空间,前驱是7所在位置,后继是6所在位置...不要忘了修改 7和6 的前驱和后继...
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define N 100009 6 using namespace std; 7 int n,dis[N],la,lheap,heap[N<<3],pos[N<<3],K,now,point[N<<3][2],prev,next; 8 long long a[N<<3],ans; 9 inline void push(int x) 10 { 11 int i=++lheap; 12 heap[i]=x; 13 pos[x]=i;//pos用来记录链表a[]第x个位置 在堆中的位置 14 while (i>1) 15 if (a[ heap[i] ]<a[ heap[i/2] ]) 16 { 17 swap(heap[i],heap[i/2]); 18 swap(pos[ heap[i] ],pos[ heap[i/2] ]); 19 i>>=1; 20 } 21 else return; 22 } 23 inline int del(int x)//这里删除的时候,仅仅是赋了一个极大值,塞到堆最靠下的位置啦~ 24 { 25 int i=pos[x]; 26 a[x]=1e12; 27 while (i*2<=lheap) 28 { 29 int p=i*2; 30 if ( a[ heap[p+1] ]<a[ heap[p] ] ) p++; 31 if ( a[ heap[p] ]<a[ heap[i] ] ) 32 { 33 swap(heap[i],heap[p]); 34 swap(pos[ heap[i] ],pos[ heap[p] ]); 35 i=p; 36 } 37 else break; 38 } 39 } 40 inline int pop() 41 { 42 int i=1,rt=heap[1]; 43 heap[1]=heap[lheap--]; 44 pos[ heap[1] ]=1; 45 while (i*2<=lheap) 46 { 47 int p=i*2; 48 if ( a[ heap[p+1] ]<a[ heap[p] ] ) p++; 49 if ( a[ heap[p] ]<a[ heap[i] ] ) 50 { 51 swap(heap[i],heap[p]); 52 swap(pos[ heap[i] ],pos[ heap[p] ]); 53 i=p; 54 } 55 else return rt; 56 } 57 return rt; 58 } 59 int main() 60 { 61 int i,j,k; 62 cin>>n>>K>>dis[1]; 63 a[0]=a[n]=1e12;//边界赋一个极大值...(因为a[]中是n-1个数,后边界显然是n) 64 point[0][1]=1,point[0][0]=0,point[n][1]=n,point[n][0]=n-1;//题解中有解释... 65 push(0),push(n); 66 for (i=1;i<n;i++) 67 { 68 scanf("%d",&dis[i+1]); 69 a[i]=dis[i+1]-dis[i]; 70 point[i][0]=i-1; 71 point[i][1]=i+1; 72 push(i); 73 } 74 75 for (la=n;K;K--) 76 { 77 ans+=a[now=pop()];//pop完了后,要先push,因为堆是在不断扩展的,pop后那个元素依然在heap 78 prev=point[now][0],next=point[now][1]; //数组的最后一个,push后可以把它覆盖 79 a[++la]=a[prev]+a[next]-a[now]; 80 81 point[la][0]=point[prev][0]; 82 point[ point[prev][0] ][1]=la; 83 point[la][1]=point[next][1]; 84 point[ point[next][1] ][0]=la; 85 86 push(la);//push要在del之前, 87 del( prev ),del( next ); 88 } 89 cout<<ans<<endl; 90 }