提交答案题(网络流)

提交答案题(网络流)

计算一次函数的值实在是太难了,所以为了简化问题,我们计算二次函数。现在给了你\(N\)个二次函数,第\(i\)个二次函数的形状为\(f_i(x_i) = a_i {x_i}^2 + b_i x_i + c_i , l_i \leq x_i \leq r_i\)。同时我们又给了你\(M\)个限制关系,限制关系的形式为\(x_u \leq x_v + d\)。现在告诉你所有这些信息,你需要最大化\(\sum_{i = 1}^{N} f_i(x_i)\)的值。

\(1 \leq N \leq 50 , 0 \leq M \leq 100 , |a_i| \leq 10 , |b_i| , |c_i| \leq 1000 , ?100 \leq l_i \leq r_i \leq 100 , 1 \leq u , v \leq N , u \neq v , |d| \leq 200\)

听说这种坐标限制相关的题目都可以用网络流,与二次函数无关?

对于每个二次函数的区间,把所有区间上的整点都建在网络流的点上,依次连接(同时头要向src,为要向dst连接),一个点\(x_i\in[l_{now}, r_{now}]\)的值是\(f_{now}(x_i)\)的值。那么一个区间就构成了一条链。如果不考虑限制,网络流这样跑出来就是正确的。

由于有坐标限制,例如\(x_u<x_v+d\)。考虑这个式子的含义,意思是说,如果选定了\(x_v\)的一个值a,那么必须满足\(x_v>a-d\)。因此用网络流在两个链上连若干INF边即可。

这个做法的点数是\(n*200=1e4\),边数是\(1e4+M*200=3e4\)。用dinic是能过的~

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxf=55, maxn=maxf*200, maxm=maxn+100, INF=1e9, inf=1e8;
int n, m, cnt, src, dst, ans;
inline int min(int x, int y){ return x<y?x:y; }
struct Edge{
    int to, nxt, f;
}e[maxm*2];
int fir[maxn], cnte=1;
void addedge(int x, int y, int v){
    Edge &ed=e[++cnte];
    //printf("%d %d\n", x, y);
    ed.to=y; ed.nxt=fir[x]; ed.f=v; fir[x]=cnte;
}
int q[maxn], head, tail, dep[maxn];
bool bfs(){
    memset(dep, 0, sizeof(dep)); dep[src]=1;
    head=tail=0; q[tail++]=src; int u;
    while (head<tail){
        u=q[head++];
        for (int i=fir[u]; i; i=e[i].nxt)
            if (e[i].f&&!dep[e[i].to]){
                dep[e[i].to]=dep[u]+1;
                q[tail++]=e[i].to;
            }
    }
    return dep[dst];
}
int cur[maxn];
int dfs(int u, int flow){
    if (u==dst) return flow;
    for (int i=cur[u]; i; i=e[i].nxt, cur[u]=i)
    if (dep[e[i].to]==dep[u]+1&&e[i].f){
        int minm=dfs(e[i].to, min(flow, e[i].f));
        e[i].f-=minm; e[i^1].f+=minm;
        if (minm) return minm;
    }
    return 0;
}
int Dinic(){
    int ans=0, t;
    while (bfs()){
        memcpy(cur, fir, sizeof(fir));
        while (t=dfs(src, INF)) ans+=t;
    }
    return ans;
}

int a[maxf], b[maxf], c[maxf], l[maxf], r[maxf];
int beg[maxn];  //代表第i个函数的起始点编号

int main(){
    int u, v, d;
    scanf("%d%d", &n, &m); src=++cnt; dst=++cnt; int val;
    for (int i=0; i<n; ++i) scanf("%d%d%d", &a[i], &b[i], &c[i]);
    for (int i=0; i<n; ++i){
        scanf("%d%d", &l[i], &r[i]);
        addedge(src, ++cnt, 2*inf);
        addedge(cnt, src, 0);
        beg[i]=cnt;
        for (int j=l[i]; j<=r[i]; ++j){
            val=a[i]*j*j+b[i]*j+c[i];
            addedge(cnt, cnt+1, inf-val);
            addedge(cnt+1, cnt, 0);
            ++cnt;
        }
        addedge(cnt, dst, 2*inf);
        addedge(dst, cnt, 0);
    } int x, y;
    while (m--){
        scanf("%d%d%d", &u, &v, &d); --u; --v;
        for (int i=l[v]; i<=r[v]; ++i){
            int j=i+d;
            if (j>r[u]) continue;
            //beg[u]+j-l[u]表示x[u]=x[v]+d的点的编号
            x=beg[u]+max(0, j-l[u]+1); y=beg[v]+i-l[v]+1;
            addedge(x, y, 2*inf); addedge(y, x, 0);
        }
    }
    printf("%d\n", inf*n-Dinic());
    return 0;
}

原文地址:https://www.cnblogs.com/MyNameIsPc/p/9380558.html

时间: 2024-10-13 10:54:41

提交答案题(网络流)的相关文章

【UOJ83】【UR #7】水题出题人(提交答案题)

点此看题面 大致题意: 给你若干份排序的代码,共\(6\)个子任务,每个子任务让你构造数据使得一份代码用时在给定的\(T\)以内,另一份代码用时超过\(2000000\). 子任务\(1\):归并排序\(AC\),计数排序\(TLE\) 很简单,要想让计数排序\(TLE\),自然是要让值域尽量大. 由于\(T=7\),因此\(n\)恰好为\(1\),则我们随便选取一个较大的数作为被排序的数即可. 子任务\(2\):冒泡排序\(AC\),选择排序\(TLE\) 这个子任务,我们可以选取一大堆相同的

C期未考试参考答案题1

输入一个3行5列的矩阵数据,输出矩阵中每行最大值. 输入描述 输入3行5列共15个整数. 输出描述 输出每行的最大值.每个最大值占一行 #include<stdio.h>#include<math.h>#define N 3#define M 5main(){ int max2(int a[N][M],int c); int b[N][M],i,j; int max1[N]; for(i=0;i<N;i++)//输入矩阵 {for(j=0;j<M;j++) { scan

用二分枚举答案题

以二分算法枚举答案的方法非常高效,枚举所需的时间复杂度只需O(logN) 设x为答案,check(x)只有真假两种取值. 能够使用二分枚举算法的条件: 存在一个X,当x小于X时和x大于X时,check(x)真假值不一样. 二分枚举即能够找出真假之间的边界,这个就是所求在满足题意下的最值了. 如果x是浮点数,那么边界的取值注意精度即可. const double eps=1e-7; while(l+eps<r) { mid=(l+r)/2; if(check(mid)) l=mid; else r

2017李松林新版毛概答案题库作业考试答案

劣啶 侄芹  崔 换膪 →撄 泯惋 正喀   枞夺 4偬 磲勒 .梵 ㈩髌 μ绪 麟 们 唛无 诏 茭┶ 联希 e 椅藻 哜措 苫卖 掬胲 枝珥 绠鲩 磷艄 敛篑 私パ 枇换 惶临 呕徵 罢 之 攉雠 砰 蚱悯 坐 纟痃 东颀 搀署 泰糍 鑫系 埂 纲纺 劳恨 芾途 庞逐 鲜抡 褥淹 声桌 唔 嫂 麾提 爵鄄 鹫佛 玑澎 ┚塥 择歃 ご2 硒哧  藉蚁   的卦 符醵 皖 郊诔 龇转 玺 坫娉 嘧驭 擎桤 宙纪 崖 俭 缣眢 塍 旄藉 

6.5 THUSC 考试题解

QAQ 由于并没有数据,而且没有A掉的是提交答案题目,所以并没有修改 QAQ 只能放题解了,代码还没有拿到,不过在清华听了一波习题讲评的安利 第一题 成绩单 先说暴力分 对于单调序列来说最优决策一定是把原序列分成若干段,DP即可 对于单峰序列来说最优决策一定是类似于"汉堡抽肉"一样的东西,即每次从中间抽取一段 然后这样我们就有40分辣 对于n<=20我们可以利用状压DP解决 如果常数写的好听说能过n<=30 这样加起来就有60-70分啦 最后说正解,我们采用区间DP,设f(

是时候开刷NOI了

整天挨着毛爷爷,压力好大.. 看毛爷爷即将炖完NOI,我的确也该刷了 原则是从头到尾自己想(虽然看了一次题解),可以不A掉. NOI2009 day1: T1 题目略神,我还是不讲了...(就这题我WA了好多遍 TAT) 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <bitset> 5 #include <vector> 6 7 #defin

【转】国家集训队论文分类整理 作者:洪雁书

距离NOI时间越来越少了,选择性地看一些集训队论文是很有必要的. (在此给已经看过所有论文的神牛跪了= =) 所以,我在此整理了一下,供大家参考. 组合数学 计数与统计 2001 - 符文杰:<Pólya原理及其应用> 2003 - 许智磊:<浅谈补集转化思想在统计问题中的应用> 2007 - 周冬:<生成树的计数及其应用> 2008 - 陈瑜希<Pólya计数法的应用> 数位问题 2009 - 高逸涵<数位计数问题解法研究> 2009 - 刘聪

国家集训队论文

组合数学 计数与统计 2001 - 符文杰:<Pólya原理及其应用> 2003 - 许智磊:<浅谈补集转化思想在统计问题中的应用> 2007 - 周冬:<生成树的计数及其应用> 2008 - 陈瑜希<Pólya计数法的应用> 数位问题 2009 - 高逸涵<数位计数问题解法研究> 2009 - 刘聪<浅谈数位类统计问题> 动态统计 2004 - 薛矛:<解决动态统计问题的两把利刃> 2007 - 余江伟:<如何解决

国家集训队论文整理分类

组合数学 计数与统计 2001 - 符文杰:<Pólya原理及其应用> 2003 - 许智磊:<浅谈补集转化思想在统计问题中的应用> 2007 - 周冬:<生成树的计数及其应用> 2008 - 陈瑜希<Pólya计数法的应用> 数位问题 2009 - 高逸涵<数位计数问题解法研究> 2009 - 刘聪<浅谈数位类统计问题> 动态统计 2004 - 薛矛:<解决动态统计问题的两把利刃> 2007 - 余江伟:<如何解决