Codefoces802O April Fools' Problem (hard)

Problem

Codeforces

Solution

这鬼题为什么一脸可以DP的样子?我D了半天都没列出方程QAQ
队长:这不是显然费用流吗?

惨遭嘲讽

队长:我就看了一会


从费用流模型入手,那么就是就是把A点,向每一个后面的B点连边,这样边是 O ( n 2 ) O(n^2) O(n2)级别的。然而其实可以优化这些边,把每个B点都向后连INF,费用为0的边即可。边数变为了 O ( n ) O(n) O(n)的。

然后费用流只能帮你到这了,但我们可以利用这个模型继续分析。从费用的特点来考虑,关于做的题目数量和最小花费是单调不降的。即这个函数的斜率是不降的,就可以带权二分。

找函数最小值就是直接贪心,把B都减去二分的值,然后有两种可能,一种是配对,一种是代替前面的某个被配对的B。A用小根堆维护,B用大根堆维护即可。

时间复杂度 O ( n log ⁡ n log ⁡ v ) O(n\log n\log v) O(nlognlogv)

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=500010;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
int n,k,m,L,R=2e9,cnt,a[maxn],b[maxn];
ll ans=1e18,sum;
struct Heap{
	int p,a[maxn];
	void push(int x){a[++p]=x;push_heap(a+1,a+p+1);}
	void pop(){pop_heap(a+1,a+p+1);--p;}
}H;
struct GHeap{
	int p,a[maxn];
	void push(int x){a[++p]=x;push_heap(a+1,a+p+1,greater<int>() );}
	void pop(){pop_heap(a+1,a+p+1,greater<int>() );--p;}
}GH;
void check(int m)
{
	int x1,x2;
	H.p=GH.p=0;cnt=0;sum=0ll;
	for(int i=1;i<=n;i++)
	{
		x2=2e9;
		GH.push(a[i]);
		x1=b[i]-m+GH.a[1];//insert
		if(H.p>0) x2=b[i]-H.a[1];//replace
		if(x1>=0&&x2>=0) continue;
		if(x1<=x2)
		{
			++cnt;sum+=x1;
			GH.pop();H.push(b[i]);
		}
		if(x1>x2){sum+=x2;H.pop();H.push(b[i]);}
	}
}
int main()
{
	read(n);read(k);
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<=n;i++) read(b[i]);
	while(L<=R)
	{
		m=((ll)L+R)>>1;check(m);
		if(cnt>=k)
		{
			ans=sum+(ll)k*m;
			R=m-1;
		}
		else L=m+1;
	}
	printf("%lld\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值