Description

你的公司接到了一批订单. 订单要求你的公司提供 \(n\) 类产品, 产品被编号为 \(1 \sim n\), 其中第 \(i\) 类产品共需要 \(C_i\) 件. 公司共有 \(m\) 名员工, 员工被编号为 \(1 \sim m\) 员工能够制造的产品种类有所区别. 一件产品必须完整地由一名员工制造, 不可以由某名 员工制造一部分配件后, 再转交给另外一名员工继续进行制造.

我们用一个由 \(0\)\(1\) 组成的 \(m \times n\) 的矩阵 \(A\) 来描述每名员工能够制造哪些产品. 矩阵的行和列分别被编号为 \(1 \sim m\)\(1 \sim n\),\(A_{i,j}\)\(1\) 表示员工 \(i\) 能够制造产品 \(j\), 为 \(0\) 表示员工 \(i\) 不能制造产品 \(j\).

如果公司分配了过多工作给一名员工, 这名员工会变得不高兴. 我们用愤怒值来描述某名员工的心情状态. 愤怒值越高, 表示这名员工心情越不爽, 愤怒值越低, 表示这名员工心情 越愉快.

员工的愤怒值与他被安排制造的产品数量存在某函数关系, 鉴于员工们的承受能力不同, 不同员工之间的函数关系也是有所区别的. 对于员工 \(i\), 他的愤怒值与产品数量之间的函数是一个 \(S_{i}+1\) 段的分段函数. 当他制造第 \(1 \sim Ti,1\) 件产品时, 每件产品会使他的愤怒值增加 \(W_{i,1}\), 当他制造第 \(T_{i,1}+1 \sim T_{i,2}\) 件产品时, 每件产品会使他的愤怒值增加 \(W_{i,2} \ldots\)

为描述方便, 设 \(T_{i,0} = 0, T_i, S_{i+1} = \infty\), 那么当他制造第 \(T_{i,j-1}+1 \sim Ti,j\) 件产品时, 每件产品会使他的愤怒值增加 \(Wi,j (1 \leq j \leq S_{i}+1)\). 你的任务是制定出一个产品的分配方案, 使得订单条件被满足, 并且所有员工的愤怒值之和 最小. 由于我们并不想使用 Special Judge, 也为了使选手有更多的时间研究其他两道题目, 你只需要输出最小的愤怒值之和就可以了.

Input

第一行包含两个正整数 \(m\)\(n\), 分别表示员工数量和产品的种类数; 第二行包含 \(n\) 个正整数, 第 \(i\) 个正整数为 \(C_i\);

以下 \(m\) 行每行 \(n\) 个整数描述矩阵 \(A\);

下面 \(m\) 个部分, 第 \(i\) 部分描述员工 \(i\) 的愤怒值与产品数量的函数关系. 每一部分 由三行组成: 第一行为一个非负整数 \(S_i\), 第二行包含 \(S_i\) 个正整数, 其中第 \(j\) 个正整数为 \(T_{i,j}\), 如果 \(S_i = 0\) 那么输入将不会留空行 (即这一部分只由两行组成). 第三行包含 \(S_{i+1}\) 个正整数, 其中第 \(j\) 个正整数为 \(W_{i,j}\).

Output

仅输出一个整数, 表示最小的愤怒值之和.

Sample Input

2 3
2 2 2
1 1 0
0 0 1
1
2
1 10
1
2
1 6

Sample Output

24

Data Range

对于所有数据,\(1 \leq m, n \leq 250, 0 \leq S_i \leq 5, 0 \leq A_{i,j} \leq 1, 0 \lt T_{i,j} \lt T_{i,j+1}, 0 \lt W_{i,j} \lt W_{i,j+1}\), 所有数据不大于 \(10^8\)

Explanation

一眼瞪出来的费用流, 由于 SPFA 的贪心性质, 我们可以假定每一次增广的时候总会选取 最佳的那一段路程或线段, 所以我们把分段函数分段, 就建完费用流了

把 1 写成 i 调了好久~

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cstring>

using namespace std;
typedef long long lli;
const int maxn = 2010, maxm = 500100, maxN = 260, maxS = 11;
const lli infinit = 0x007f7f7f7f7f7f7fll;
const int infinit_i = 0x7fffffff;

class MaxFlowMinCost
{
public:
    struct edge
    {
        int u, v;
        lli flow, cost;
        edge *next, *rev;
    };
    int n, s, t, ecnt;
    lli dist[maxn];
    edge *edges[maxn], epool[maxm], *from[maxn];
    void add_edge(int u, int v, lli flow, lli cost)
    {
        edge *p = &epool[++ecnt],
             *q = &epool[++ecnt];
        p->u = u; p->v = v; p->flow = flow; p->cost = cost;
        p->next = edges[u]; edges[u] = p; p->rev = q;
        q->u = v; q->v = u; q->flow = 0; q->cost = -cost;
        q->next = edges[v]; edges[v] = q; q->rev = p;
        return ;
    }
    bool inque[maxn];
    bool spfa(void)
    {
        queue<int> que;
        for (int i = 1; i <= n; i++)
            inque[i] = false, dist[i] = infinit, from[i] = NULL;
        que.push(s);
        inque[s] = true, dist[s] = 0;
        while (!que.empty()) {
            int p =que.front();
            que.pop();
            for (edge *ep = edges[p]; ep; ep = ep->next)
                if (ep->flow && dist[p] + ep->cost < dist[ep->v]) {
                    dist[ep->v] = dist[p] + ep->cost;
                    from[ep->v] = ep;
                    if (!inque[ep->v]) {
                        que.push(ep->v);
                        inque[ep->v] = true;
                    }
                }
            inque[p] = false;
        }
        if (dist[t] >= infinit)
            return false;
        return true;
    }
    lli max_flow, min_cost;
    void eval(void)
    {
        max_flow = 0;
        min_cost = 0;
        while (spfa()) {
            lli tmp = infinit;
            for (edge *ep = from[t]; ep; ep = from[ep->u])
                tmp = min(tmp, ep->flow);
            for (edge *ep = from[t]; ep; ep = from[ep->u])
                ep->flow -= tmp,
                ep->rev->flow += tmp;
            max_flow += tmp;
            min_cost += tmp * dist[t];
        }
        return ;
    }
} graph;

int n, m;
int C[maxN], A[maxN][maxN],
    S[maxN], T[maxN][maxS], W[maxN][maxS];

int main(int argc, char** argv)
{
    scanf("%d%d", &m, &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &C[i]);
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= n; j++)
            scanf("%d", &A[i][j]);
    // Reading functions
    for (int i = 1; i <= m; i++) {
        scanf("%d", &S[i]);
        for (int j = 1; j <= S[i]; j++)
            scanf("%d", &T[i][j]);
        T[i][S[i] + 1] = infinit_i;
        for (int j = 1; j <= S[i] + 1; j++)
            scanf("%d", &W[i][j]);
    }
    // Building graph according to MCMF
    graph.n = n + m + 2;
    graph.s = n + m + 1;
    graph.t = n + m + 2;
    for (int i = 1; i <= n; i++)
        graph.add_edge(graph.s, i, C[i], 0);
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= n; j++)
            if (A[i][j])
                graph.add_edge(j, n + i, infinit, 0);
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= S[i] + 1; j++)
            graph.add_edge(n + i, graph.t, T[i][j] - T[i][j - 1], W[i][j]);
    // Evaluating
    graph.eval();
    lli res = graph.min_cost;
    printf("%lld\n", res);
    return 0;
}