• AtCoder keyence2019_e


    洛谷的AtC接口貌似坏掉了,水不了这道紫题了,但是题解还是可以水的(大雾

    洛谷题目页面传送门 & AtC题目页面传送门

    (n)个点,第(i)个点的权值为(a_i)。给定常数(d),在点(i,j)之间连边的代价是(|i-j|d+a_i+a_j)。求将它们连成一棵树的最小代价。

    (ninleft[1,10^5 ight])

    首先不难发现,原题相当于,求完全图的MST的权,其中点(i,j)之间的边权为(|i-j|d+a_i+a_j)。如果直接Kruskal的话,建图就要爆炸,边数是(mathrm O!left(n^2 ight))的。考虑用某些MST的奇技淫巧。

    我们的目的是,尽可能删掉一些边,留下尽量少的边,使得MST的权不变。

    注意到这样一条经典的性质:MST不可能包含一个环上所有的最大边。证明很简单:反证法。若包含,则随意去掉一个环上的最大边((x,y)),此时整棵树断成两部分,(x,y)在不同的部分。由于是个环,那么环上一定有一条反向的不包含 ((x,y))(x o y)路径,连接两个部分,这条路径上显然有连接两部分的另一条边,选上它得到另一棵生成树。这条边边权严格小于((x,y))的权,所以原树不可能是MST。得证。

    不妨研究一些环,看能不能用这个性质删边。从最简单的三元环入手。

    首先,(i<j)间边权可变形为(a_i-id+a_j+jd)。令(A_i=a_i-id,B_i=a_i+id),那么就是(A_i+B_j)。对于三元环((i,j,k))

    1. (i<j<k)时,((i,j))非严格最大当且仅当(B_jgeq B_k,A_i+B_jgeq A_j+B_k)。注意到(B_jgeq B_k,A_igeq A_j)显然是它的充分条件,我们完全可以只用这个,正确性健在;
    2. (i<k<j)时,((i,j))非严格最大当且仅当(B_jgeq B_k,A_igeq A_k)
    3. (k<i<j)时,((i,j))非严格最大当且仅当(A_i+B_jgeq A_k+B_i,A_igeq A_k)。同(1),充分条件是(B_jgeq B_i,A_igeq A_k)

    (1,2)放一起研究,可以得出共同点:(B_jgeq B_k,A_igeq A_{ ext{位置在第2的点}})。那么我们想,对于一堆在(i)右边的、(A)(leq A_i)的点,我们一定可以把它们连向(i)的边互相毙,毙的只剩一个,即那个(B)值最小的。

    这看起来很成立,但是似乎仅在严格的时候成立,因为根据上述性质,只有最大边唯一的时候,才可以肆无忌惮地毙掉最大边,否则一般情况下需要保证其他最大边健在。不过在这里的特殊情况,即使非严格也是成立的。证明:若不存在任意一个MST使得它包含任意一条被毙掉的边则已,否则选择一个:设留下来的点是(x)。对于任意一个被毙掉的还在MST里的边((i,y)),若((x,y))不在MST里即可直接换成((x,y)),否则((i,x))一定不在(因为生成树里不可能有环),但是不能直接换成((i,x)),因为它是唯一的,而有那么多被毙掉的边等着换呢。如此,只要证满足((i,y),(x,y))都在MST里的被毙掉的边((i,y))最多只有一个。这是显然的,因为若有两个(y_0,y_1),则((i,x,y_0,y_1))构成四元环。得证。

    同理,一堆在(i)左边的、(B)(leq B_i)的点,我们也可以留下(A)值最小的,其他都毙掉。

    不过这样,两个毙法一综合,问题又出现了。。有的点对((i,j)(i<j)),它们之间的边可能会被考虑两次((j)左边和(i)右边),这样就可能是即被删掉,又被留下来的状态。这里有一个巧妙的处理方法:观察(A_igeq A_j),展开得(a_i-idgeq a_j-jd),注意到因为(i<j),所以(-id>-jd),那么充分条件就是(a_igeq a_j)。同理,(B_jgeq B_i)的充分条件是(a_jgeq a_i)。在(a)值互不相同的时候,两者恰好只能选一个,也就是说完全图里每条边恰好被考虑了一遍,就不存在问题了。如果(a)值有相同的呢?只需要再加第二个关键字:位置,这样就一定能比出大小了。

    如此,每个点两侧最多各有一条边留下来,边数复杂度(mathrm O(n))。再用BIT xjb随便维护一下建图,然后Kruskal,时间复杂度(mathrm O(nlog n))

    代码也没啥需要说的:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define mp make_pair
    #define X first
    #define Y second
    #define pb push_back
    const int inf=0x3f3f3f3f3f3f3f3f;
    int lowbit(int x){return x&-x;}
    const int N=200000;
    int n,d;
    int a[N+1];
    pair<int,int> p[N+1];
    struct bitree{
    	pair<int,int> mn[N+1];
    	void init(){
    		for(int i=1;i<=n;i++)mn[i]=mp(inf,0);
    	}
    	void chkmn(int x,pair<int,int> v){
    		while(x<=n)mn[x]=min(mn[x],v),x+=lowbit(x);
    	}
    	int Mn(int x){
    		pair<int,int> res(inf,0);
    		while(x)res=min(res,mn[x]),x-=lowbit(x);
    		return res.Y;
    	}
    }bit,bit_r;
    vector<pair<int,int> > eg;
    struct ufset{//并查集 
    	int fa[N+1];
    	void init(){memset(fa,0,sizeof(fa));}
    	int root(int x){return fa[x]?fa[x]=root(fa[x]):x;}
    	bool mrg(int x,int y){
    		x=root(x);y=root(y);
    		if(x==y)return false;
    		return fa[x]=y,true;
    	}
    }ufs;
    int cst(pair<int,int> x){//边权 
    	if(x.X>x.Y)swap(x.X,x.Y);
    	return a[x.X]+a[x.Y]+(x.Y-x.X)*d;
    }
    bool cmp(pair<int,int> x,pair<int,int> y){
    	return cst(x)<cst(y);
    }
    int kruskal(){//Kruskal 
    	sort(eg.begin(),eg.end(),cmp);
    	int ans=0;
    //	for(int i=0;i<eg.size();i++)printf("%lld %lld
    ",eg[i].X,eg[i].Y);
    	for(int i=0;i<eg.size();i++)ans+=ufs.mrg(eg[i].X,eg[i].Y)*cst(eg[i]);
    	return ans;
    }
    signed main(){
    	cin>>n>>d;
    	for(int i=1;i<=n;i++)scanf("%lld",a+i),p[i]=mp(a[i],i);
    	sort(p+1,p+n+1);
    	bit.init();bit_r.init();
    	for(int i=1;i<=n;i++){//BIT建图 
    		int mn1=bit.Mn(p[i].Y-1),mn2=bit_r.Mn(n-p[i].Y);
    		if(mn1)eg.pb(mp(p[i].Y,mn1));
    		if(mn2)eg.pb(mp(p[i].Y,mn2));
    		bit.chkmn(p[i].Y,mp(p[i].X-p[i].Y*d,p[i].Y));bit_r.chkmn(n-p[i].Y+1,mp(p[i].X+p[i].Y*d,p[i].Y));
    	} 
    	cout<<kruskal();
    	return 0;
    }
    

    官方题解还给出了另一种分治的方法。就是说,把边分成在左半边内、在右半边内、横跨两半边三类,处理横跨两半边的,另外两种递归下去。考虑如何处理。我们选择左半边(A)值最小的点(x)连所有右半边的点,选择右半边(B)值最小的点(y)连所有左半边的点,这样一来其他所有的横跨两半边的边((x',y'))都被毙掉了,因为((x,y),(x,y'),(x',y))都在,((x',y'))成了环中最大的边。至于严格非严格的问题,xjb再证一下即可。这是在四元环上作文章的。边数复杂度(mathrm O(nlog n)),时间复杂度(mathrm O!left(nlog^2n ight))

    代码没写。应该很好写?

    综上所述,下次遇到这样的人类智慧题我还是做不出来。

  • 相关阅读:
    区块链中的随机数 nonce
    SaaS(软件即服务)、PaaS(平台即服务)、IaaS(基础架构即服务)、BaaS(区块链即服务)
    程序插桩简介
    侧链技术
    闪电/雷电网络
    Ubuntu16.04安装/升级openssl到1.1版本
    Ubuntu16.04升级Python3及其pip3并切换为默认版本
    Python——/usr/bin/env: ‘python(3) ’: No such file or directory
    TCP通信功能 (agent功能)
    gin框架web操作数据库
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/AtCoder-keyence2019-e.html
Copyright © 2020-2023  润新知