首先有一些神奇的东西。
有一类问题可以转化成形如$minimizesum_{u,v} max(h_u-h_v+w_{u,v},0)c_{u,v}$,其中h是任意值
然后这个和最大费用循环流等价,就是u到v连一条$(c_{u,v},w_{u,v})$的边,然后消一下正环,直接跑就完了。。。
有一道例题 CF1307G
大概是要求一个这样的东西
$minimize d_n-d_1$
$s.t.$ $d_v<=d_u+w_{u,v}+x_{u,v},sum x_{u,v}<=x,x_{u,v}>=0$
然后如果设答案下届为L,问题转化为
$minimize sum x_{u,v}$
$s.t.$ $d_v<=d_u+w_{u,v}+x_{u,v},d_n-d_1>=L,x_{u,v}>=0$
这个可以试着转化一下就是上面的形式了(将$d$视为$h$)
但是并不能二分,可以先不建流量为L的边直接跑,然后可以得到一个费用关于流量的函数f(x)。
我们要求加上一个斜率为L的直线,使得$forall f(i)+L*i<=x$均成立,直接连立解出L即可。
复杂度$O(n^4+qn)$
#include<bits/stdc++.h> using namespace std; const int maxm=55*55*55; int head[maxm],to[maxm],nxt[maxm],val[maxm],fw[maxm],cnt=1,t[maxm]; int q[maxm],d[maxm],n,m,pre[maxm]; bool v[maxm]; inline void link(int a,int b,int c){ to[++cnt]=b,nxt[cnt]=head[a],head[a]=cnt,fw[cnt]=1,val[cnt]=c; to[++cnt]=a,nxt[cnt]=head[b],head[b]=cnt,val[cnt]=-c; } inline bool SPFA(){ for(int i=1;i<=n;++i) d[i]=-0x3f3f3f3f;d[n]=0; int h,t;q[h=t=0]=n; while(h<=t){ int x=q[h++]; for(int i=head[x];i;i=nxt[i]) if(fw[i]){ int y=to[i]; if(d[y]<d[x]+val[i]) { pre[y]=i,d[y]=d[x]+val[i]; if(!v[y]) q[++t]=y,v[y]=1; } } v[x]=0; } return d[1]!=-0x3f3f3f3f; } int main(){ cin>>n>>m;int res=0,tot=0,q; while(m--){ int a,b,c;cin>>a>>b>>c; link(b,a,-c); } while(SPFA()){ int res=0; for(int i=1;i!=n;i=to[pre[i]^1]) res+=val[pre[i]],--fw[pre[i]],++fw[pre[i]^1]; t[++tot]=res;t[tot]+=t[tot-1];//cout<<t[tot]<<endl; }cin>>q;//cout<<tot<<endl; while(q--){ int x;scanf("%d",&x); double ans=1e16; for(int i=1;i<=tot;++i) ans=min(ans,1.0*(x-t[i])/i);//,cout<<x-t[i]<<endl; printf("%lf ",ans); } return 0; }
有一个东西叫保序回归,他的模型大概是有n个变量$x_i$,有m个限制形如要求$y_i<y_j$,变量的变化有代价函数f(x),然后要最小化$sum f(|y_i-x_i|)$
做法:首先整体二分,假设当前参数为$solve(l,r,S)$,然后$mid=l+r>>1$,考虑以mid为界来划分S集合,也就是将S划分为A和B。
就是以是否超过mid为界,那么考虑每个点,如果变成<=mid的,就和源点连一条$f(|mid-x_i|)$,再和汇点连一条$f(|mid+1-x_i|)$的边,
然后对于那些限制可以直接看成最大权闭合子图,最后看和源汇点的联通来判断分到左右儿子,边界有一些特判。
(一点都不会证明)
然后有一道ZJOI的题 「ZJOI2020」抽卡
咕了