首先,明显的网络流。那么如何建边,对于每个二次函数在[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 ' ' #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; }