码迷,mamicode.com
首页 > 其他好文 > 详细

杂题选讲

时间:2020-07-28 00:23:04      阅读:64      评论:0      收藏:0      [点我收藏+]

标签:pac   ora   一点   参数   size   最小化   print   for   spfa   

首先有一些神奇的东西。

有一类问题可以转化成形如$minimize\sum_{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\n",ans);
    }
    return 0;
}
View Code

 

有一个东西叫保序回归,他的模型大概是有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」抽卡

咕了

杂题选讲

标签:pac   ora   一点   参数   size   最小化   print   for   spfa   

原文地址:https://www.cnblogs.com/hzoi-kx/p/13374341.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!