zoukankan      html  css  js  c++  java
  • 数据备份

    数据备份

    在坐标轴上有n个点,第i个点的坐标为(x_i),现在请选出k对点(一个点不能同时在两对以上的点中),使每一对点的距离之和最小,求出这个最小值,(2≤n≤100000,1≤k≤n/2)

    首先容易知道的结论是一对点必然选择的是相邻的,否则在最优解,将两个点变为相邻,结果会更加优秀。

    将点的坐标从小到大排序(原题给出的就是有序的),处理出两个点间的距离,构成一个长度为n-1的数列({a_i}),以后所说的n都为({a_i})的长度,现在问题转化成从这个数列中选出k个数,不相邻的和的最小值。

    数列已经是有序的,于是我们不应该排序,最多是构造新序列,排好序,然后再构造一个序列对应其在原序列的位置,然后从小往大选,但是问题在于这个数不一定选,往后看就明白了

    朴素的最优性贪心的思想,告诉我们要从最小的数(a_i)开始,但是它一定选吗?它选了之后,最终导致与之相邻的两个数不能选择,容易知道,决策要么是选这个数(a_i),要么是选(a_{i-1},a_{i+1}),因为如果(a_{i-1},a_{i+1})只选一个,改成(a_i)会更加优秀,因此一个数字延伸多种决策,而这个数字又是最优秀的数字,考虑合并性贪心思想。

    多种决策不妨将(a_{i-1},a_i,a_{i+1})合并成一个数字,对应的值(a_{i-1}+a_{i+1}-a_i),此时答案累加(a_i),如果接下来选了(a_{i-1}+a_{i+1}-a_i),表示选了(a_{i-1}+a_{i+1}),否则表示选了(a_i),正好前者对应两次选择,后者对应一次选择,于是我们成功地将多种决策合并成一种决策,三个数字合并成一个数字。

    因此按这样选择的k个数字,最好累加的答案,就是我们需要的,注意的是如果一个点没有两个点可以和它相邻,还是要删去所有与它相邻的点,表示这个点以后不会决策。

    因此对于以上思路,我们只要用小根堆维护取出最小值,用链表维护数字的合并,让小根堆顺带记录其在链表上的位置,就可以支持快速合并和查询,最终时间复杂度(O(klog(n))),这是一道很棒的思维题,但是我想不到。

    参考代码:

    #include <iostream>
    #include <cstdio>
    #define il inline
    #define ri register
    #define Size 200100
    using namespace std;
    template<class free>
    struct small{
    	free a[Size];int n;
    	il void push(free x){
    		a[++n]=x;ri int p(n);
    		while(p>1)
    			if(a[p]<a[p>>1])
    				swap(a[p],a[p>>1]),
    					p>>=1;else break;
    	}
    	il void pop(){
    		a[1]=a[n--];ri int p(1),s(2);
    		while(s<=n){
    			if(s<n&&a[s+1]<a[s])++s;
    			if(a[s]<a[p])
    				swap(a[s],a[p]),p=s,s=p<<1;
    			else break;
    		}
    	}
    };
    template<class free>
    struct list{
    	struct iter{
    		iter *pre,*next;free v;
    	}*head,*tail,*lt;
    	il void initialize(){
    		head=new iter(),tail=new iter();
    		head->next=tail,tail->pre=head;
    	}
    	il void insert(iter*p,free v){
    		lt=new iter{p->pre,p,v};
    		p->pre->next=lt,p->pre=lt;
    	}
    	il void erase(iter*p){
    		p->pre->next=p->next;
    		p->next->pre=p->pre;
    		p->v=-1;
    	}
    };
    struct er{
    	int d;list<int>::iter *p;
    	il bool operator<(const er&x)const{
    		return d<x.d;
    	}
    };
    int s[Size];
    list<int>L;small<er>S;
    list<int>::iter *m,*l,*r;
    il void read(int&);
    int main(){
    	int n,k,ans(0);
    	read(n),read(k),L.initialize();
    	for(int i(1);i<=n;++i)read(s[i]);
    	--n;for(int i(1);i<=n;++i)
    			s[i]=s[i+1]-s[i],L.insert(L.tail,s[i]),
    				S.push((er){s[i],L.tail->pre});
    	for(int i(1);i<=k;++i){
    		while(m=S.a[1].p,m->v==-1)S.pop();
    		l=m->pre,r=m->next,ans+=m->v;
    		if(l==L.head&&r==L.tail)break;
    		if(l==L.head)L.erase(r),L.erase(m);
    		else if(r==L.tail)L.erase(l),L.erase(m);
    		else{
    			L.insert(r,l->v+r->v-m->v);
    			L.erase(m),m=r->pre,S.push({m->v,m});
    			L.erase(l),L.erase(r);
    		}S.pop();
    	}printf("%d",ans);
    	return 0;
    }
    il void read(int &x){
    	x^=x;ri char c;while(c=getchar(),c<'0'||c>'9');
    	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    
    
  • 相关阅读:
    TDengine在上海电气储能智慧运维系统中的应用
    一文带你理解TDengine中的缓存技术
    taosAdapter正式发布:支持从OpenTSDB向TDengine无缝迁移
    TDengine 在中节能风力发电运维系统中的落地实践
    格创东智选择 TDengine,实现海量数据实时全生命周期管理
    TDengine 在水电厂畸变波形分析及故障预判系统中的应用
    使用wireshark抓包分析TCP三次握手
    K8s中 蓝绿部署、金丝雀发布、滚动更新汇总
    K8s运维锦囊,19个常见故障解决方法
    一次由 Kubernetes HostPort 引发的服务故障排错记实
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11248339.html
Copyright © 2011-2022 走看看