[SDOI2011]工作安排

来源:互联网 发布:shake it 下载 编辑:程序博客网 时间:2024/05/01 16:04

刷水题刷的停不下来233

水费用流

考虑每个w[i]是严格单调递增,于是只需要把每个人拆成s[i]+1个点,产品与人连边时对应相应费用,每个人与汇点连边对应最大数量,剩下的交给spfa

数据需要long long

Code:

#include <cstdio>#include <queue>#include <bitset>#include <cstring>using namespace std;queue<int> Q;#define N 10001#define M 200001#define INF 0x7FFFFFFFstruct E{int to, f, c, next, op;}G[M];int cnt, point[N], path[N], prev[N], n, m, can[251][251], s[251], t[251][251], w[251][251], S, T, bh[251][251], D[N];bitset<N> vis;inline void add(int u, int v, int f, int c){cnt++, G[cnt] = (E){v, f, c, point[u], cnt+1}, point[u] = cnt;cnt++, G[cnt] = (E){u, 0, -c, point[v], cnt-1}, point[v] = cnt;}inline bool spfa(){for (int i = S;i <= T; ++i)D[i] = INF;D[S] = 0;vis.reset();vis[S] = 1;prev[S] = -1;Q.push(S);while (!Q.empty()){int u = Q.front();Q.pop();for (int i = point[u];i;i = G[i].next){int v = G[i].to;if (G[i].f > 0 && D[v] > D[u] + G[i].c){D[v] = D[u] + G[i].c;prev[v] = u;path[v] = i;if (!vis[v])vis[v] = 1, Q.push(v);}}vis[u] = 0;}return D[T] != INF;}inline int argument(){int delta(INF), i, j;long long res(0);for (i = T;prev[i] != -1;i = prev[i]){j = path[i];delta = min(delta, G[j].f);}for (i = T;prev[i] != -1;i = prev[i]){j = path[i];G[j].f -= delta;G[G[j].op].f += delta;res += (long long)delta * (long long)G[j].c;}return res;}int main(){scanf("%d %d", &m, &n);S = 0;int i, j, k, tot(n);long long res(0);for (i = 1;i <= n; ++i){scanf("%d", &j);add(S, i, j, 0);}for (i = 1;i <= m; ++i)for (j = 1;j <= n; ++j)scanf("%d", &can[i][j]);for (i = 1;i <= m; ++i){scanf("%d", &s[i]);for (j = 1;j <= s[i]; ++j)scanf("%d", &t[i][j]);for (j = 1;j <= s[i]+1; ++j)bh[i][j] = ++tot;for (j = 1;j <= s[i]+1; ++j)scanf("%d", &w[i][j]);for (j = 1;j <= n; ++j)if (can[i][j])for (k = 1;k <= s[i]+1; ++k)add(j, bh[i][k], INF, w[i][k]);}T = ++tot;for (i = 1;i <= m; ++i){for (j = 1;j <= s[i]; ++j)add(bh[i][j], T, t[i][j] - t[i][j-1], 0);add(bh[i][s[i]+1], T, INF, 0);}while (spfa())res += argument();printf("%lld\n", res);return 0;}


0 0