Codefoces802O April Fools’ Problem (hard)
Problem
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;
}
版权声明:本文为As_A_Kid原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。