AGC033D Complexity

Ex - Bow Meow Optimization

n,m都为偶数时,记狗的正中为x,猫的正中为y(正中在序列中就处于两个位置之间,不与任何位置重合)

一只猫ix隔了C只狗,那么这只猫对应的代价就为Bi×(n2+C(n2C))=Bi×2C,狗的代价同理

那么对于xy之间的01,它们随意交换位置都不影响xy,所以我们可以将xy的这段区间变为x111...000y,这时代价是最小的,然后我们发现,将xy移动到10的交接处,重合,也是合法的

所以当n,m都是偶数时,其正中重合,也就是说,前一半序列中有n2只狗和m2只猫

nm有奇数时,让x左侧有n20y右侧有m21,然后用上述方法,同样可以使得xy重合

di表示对于第i个位置上的0/1,其两侧1/0之差为多少,可以发现,在xy重合的条件下,di一定恒等于n×m

证明:

考虑极端情况,序列呈00...11.|.11...00的分布情况,其中|表示x0都集中在两端,1全部靠近|,此时的代价为n×m

接下来,只需要证明,对于同一半内的相邻位置互换后,代价不变,大致分类讨论一下即可证得

因为di恒定,所以要想Ai/Bi×di最小,就得让越大的Ai/Bi分配到越少的di

所以当nm为奇数时,一定是将最大的那个Ai/Bi放到最中间,然后就可以将nm都变为偶数

n%2==1时,所有1的左/右边实际上会比将n变为偶数后的序列多一个0,所以所有的1d都要+1(当1在左半部分时,其右边的0的数量一定其左边的0的数量,所以现在其右边又多出一个0后,d+11在右半部分时同理),m%2==1同理。所以需要在一开始就给答案加上AiBi

然后对所有AiBi拉通,从大到小排序,考虑从最中间开始,贪心的放0/1,那么一定是一直向左放0直到达到数量上限,然后向右放,一直向右放1直到达到数量上限,然后向左放

向左放0/1时,其对应的代价就是2Ai/2Bi×目前左边的1/0的数量;向右放同理

复杂度O(NlogN)

#include<bits/stdc++.h>
#define ll long long
#define plb pair<ll,bool>
#define fi first
#define se second
using namespace std;
const int N=305;
int n,m,cnt,l0,l1,r0,r1;
ll a[N],b[N],suma,sumb,ans;
plb c[N<<1];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i) scanf("%lld",&a[i]),suma+=a[i];
	for(int i=1;i<=m;++i) scanf("%lld",&b[i]),sumb+=b[i];
	sort(a+1,a+n+1),sort(b+1,b+m+1);
	if(n&1) ans+=sumb; if(m&1) ans+=suma;
	for(int i=1;i<=(n>>1)<<1;++i) c[++cnt]={a[i]<<1,0};
	for(int i=1;i<=(m>>1)<<1;++i) c[++cnt]={b[i]<<1,1};
	sort(c+1,c+cnt+1),reverse(c+1,c+cnt+1);
	for(int i=1;i<=cnt;++i){
		if(c[i].se){
			if(r1<m>>1) ++r1,ans+=c[i].fi*r0;
			else ++l1,ans+=c[i].fi*l0;
		}else{
			if(l0<n>>1) ++l0,ans+=c[i].fi*l1;
			else ++r0,ans+=c[i].fi*r1; 
		}
	}
	printf("%lld\n",ans);
	return 0;
}
posted @   LuoyuSitfitw  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示