[2020杭电多校第二场]1005 New Equipments(费用流)

首先,明显的网络流。那么如何建边,对于每个二次函数在[1,m]里挑n个函数值最小的点, 这样子一共n^2个点,注意还要去重。这n^2个点其实就能使得n个二次函数(a, b, c)完全匹配。

那么流量全部设为1,费用是对应的函数值。超级源点和终点费用为0;但是,跑n次费用流时间不允许,但是你仔细想每次增广只会多1的流量,那么其实只要跑一次就行。每次增广完输出当前的费用即可,

 

//#pragma GCC optimize("-Ofast","-funroll-all-loops")
//freopen("C://std/a.in","r",stdin);
//freopen("C://std/b.txt","w",stdout);
#include<bits/stdc++.h>
#define ll long long
#define PB push_back
#define endl '\n'
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define lowbit(x) (x & (-x))
#define rep(i, a, b) for(int i = a ; i <= b ; ++ i)
#define per(i, a, b) for(int i = b ; i >= a ; -- i)
#define clr(a, b) memset(a, b, sizeof(a))
#define in insert
#define random(x) (rand()%x)
#define PII(x, y) make_pair(x, y)
#define fi first
#define se second
#define pi acos(-1)
#define re register
//std::ios::sync_with_stdio(false);
#define int long long
using namespace std;
const int maxn = 2e4 + 50;
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 5010, M = 2e5+10;
int n,m,s,T,t,v[N],e[N];
int head[N],nex[M],to[M],flow[M],tot=1;
int a[N],b[N],c[N],p[N][N],h[N],d[N],w[M],res,maxflow;
inline void ade(int a,int b,int c,int d){
    to[++tot]=b; nex[tot]=head[a]; w[tot]=d; flow[tot]=c; head[a]=tot;
}
inline void add(int a,int b,int c,int d){ade(a,b,c,d);    ade(b,a,0,-d);}
inline ll dijkstra(){
    memset(d,inf,sizeof d);    d[s]=0;    int vis[N]={0};
    priority_queue<pair<int,int> > q;    q.push({0,s});
    while(q.size()){
        int u=q.top().second;    q.pop();
        if(vis[u])    continue;    vis[u]=1;
        for(int i=head[u];i;i=nex[i]){
            if(flow[i]&&d[to[i]]>d[u]+w[i]+h[u]-h[to[i]]){
                d[to[i]]=d[u]+w[i]+h[u]-h[to[i]];
                v[to[i]]=u; e[to[i]]=i;    q.push({-d[to[i]],to[i]});
            }
        }
    }
    for(int i=1;i<=t;i++)    if(d[i]<inf)    h[i]+=d[i];
    return d[t]<inf;
}
void EK(){
    while(dijkstra()){
        int mi=inf;
        for(int i=t;i!=s;i=v[i])    mi=min(mi,1LL*flow[e[i]]);
        for(int i=t;i!=s;i=v[i])    flow[e[i]]-=mi,flow[e[i]^1]+=mi;
        res+=h[t]*mi,maxflow+=mi;
        cout << res;
        if(maxflow != n) cout << ' ';
    }
    puts("");
}
ll f(ll i, ll j){
    return j * j * a[i] + j * b[i] + c[i];
}
signed main(){
    scanf("%lld", &T);
    while(T --){
        scanf("%lld %lld", &n, &m);
        vector<int> sm;
        res = maxflow = 0; tot = 1;
        clr(head, 0);
        clr(h, 0);
        rep(i, 1, n){
            scanf("%lld %lld %lld", &a[i], &b[i], &c[i]);
            int mid = 0, k = 1;
            if(b[i] >= 0) mid = 1;
            else{
                int l = floor(-0.5 * b[i] / a[i]);
                int r = ceil(-0.5 * b[i] / a[i]);
                if(l >= 1 && l <= m){
                    if(f(i, l) < f(i, r)) mid = l;
                    else mid = r;
                }
                else mid = r;
            }
            p[i][k] = mid; sm.PB(mid);
            int l = mid - 1, r = mid + 1;
            while(k < n){
                if(f(i, l) < f(i, r)){
                    if(l >= 1 && l <= m) p[i][++k] = l --;
                    else if(r >= 1 && r <= m) p[i][++k] = r ++;
                }
                else{
                    if(r >= 1 && r <= m) p[i][++k] = r ++;
                    else if(l >= 1 && l <= m) p[i][++k] = l --;
                }
                sm.PB(p[i][k]);
            }
        }
        sort(sm.begin(), sm.end());
        sm.erase(unique(sm.begin(), sm.end()), sm.end());
        m = (int)sm.size(); s = n + m + 1; t = s + 1;
        rep(i, 1, n){
            add(s, i, 1, 0);
            rep(j, 1, n){
                int v = lower_bound(sm.begin(), sm.end(), p[i][j]) - sm.begin() + 1;
                add(i, v + n, 1, f(i, p[i][j]));
            }
        }
        rep(i, 1, m) add(i + n, t, 1, 0);
        EK();
    }

    return 0;
}
View Code

 

posted @ 2020-07-27 11:59  Ketchum  阅读(164)  评论(0编辑  收藏  举报