密钥题解分享

密钥题解

题目大意

给定一个初始01串S和一个目标01串T,每次操作可以将0->1或者1->0。每次代价是过程S中每个1的代价和,也就是说每次操作S中的1都会产生代价,要求最小代价

思路分析

因为过程中每个1都会产生代价,所以想法就是先把S中需要1->0的先进行操作,然后需要0->1的后操作,前者降序,后者升序,显然这样的代价是最小的。

我们来讨论下什么样的01需要操作

  1. S[i]==1~and~T[i]==0 这位必须操作且只能操作一次

  2. S[i]==0~and~T[i]==1 同上也必须操作

  3. S[i]==0~and~T[i]==0 肯定不会去操作,操作只会更劣势

  4. S[i]==1~and~T[i]==1 乍一看不需要进行任何操作,但别忘了,过程中的每个1都会产生代价!

这时有位大聪明就想到了,”我这种情况都进行操作不就行了“,然后你就得到WA20了,(别问我是怎么知道的,问就是我就是WA20)

所以我们就要枚举这类的操作情况的,因为要操作的话也可能会更劣势。光枚举时间肯定不过关的,我们发现这类情况我们要先操作代价比比较大的,

但后面代价小的不一定需要操作,因为多一次操作就会多一次代价!,可以想到枚举前缀。时间复杂度 O(n^2)

具体实现就是先统计必须要操作的序列,然后枚举1 1这种情况,可以用优先队列维护,但这样不方便挨个访问每个值,每次操作需要一个一个取出才行,毕竟堆只有堆顶最优,所以我们可以使用平衡树!维护,当然写过平衡树板子的人都知道,这玩意可以拿STL里的vector实现(万能的vector),代码非常简洁,长度就那WA20代码差不多,当然用优先队列和set之类也行咧。

真·核心代码

void solve(){
	for(int i=0;i<seq.size();i++){//枚举前缀
		int sum=0;
		fr.insert(lower_bound(fr.begin(),fr.end(),seq[i]),seq[i]);//1->0的序列
		ba.insert(lower_bound(ba.begin(),ba.end(),seq[i]),seq[i]);//0->1的序列
		for(int j=i+1;j<seq.size();j++)sum+=seq[j]*(fr.size()+ba.size());//不操作序列的代价 
		for(int j=0;j<fr.size();j++) sum+=(fr.size()-j-1)*fr[j];//1->0
		for(int j=0;j<ba.size();j++) sum+=(ba.size()-j)*ba[j];//0->1
		if(sum<ans) ans=sum;//更新最小代价
	}
}

别说我题解发AC代码了,这次总行了吧(恼

4 个赞

记得每个序列sort一边,seq从大到小排列,我这边忘说了(只sort一遍就可以

2 个赞

哇!好简洁,我用了两个双指针吧代码干到了1.4KB。

必须给你点赞

1 个赞

挺好的!

简洁明了

我只有四十分QoQ

2 个赞

雀石
听了大佬的讲述,瞬间悟了

1 个赞


欢迎欢迎

不错!

他的启发