时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
小Y写了一篇文章,他对自己的文笔很有自信,尤其是自己总结出了一套计算文章通顺性的公式。
文章共N段,对于文章的每一段小Y对它都能计算出一个估值,而一篇文章的不连贯值定义为
,现在小Y想要发布他的文章,但是编辑小Z让他加入一些广告,具体来说就是M段估值分别为
的新段落。小Y很头疼,想让修改后的文章依然通顺,也就是要最小化不连贯值,已知小Y加入新段落的时候不需要考虑新段落之间的顺序,但是只可以在原文章的开头段之前、结尾段之后、或两段之间加入一段新段落,每个位置只能加入最多一段。请帮助焦头烂额的小Y求出将这M个新段落全都加入之后的最小不连贯值。
输入描述:
多组数据,第一行有一个正整数表示数据组数。
之后有T组数据,每组数据第一行有两个整数。
接着有两行,其中第一行有N个正整数,表示原文章按顺序每段的估值。
第二行有M个正整数,表示新段落每段的估值。
输出描述:
对于每组数据,输出一个整数表示求出的最小不连贯值。
示例1
输入
2 4 3 1 6 5 2 3 1 4 4 2 1 2 4 3 10 10
输出
3 7
说明
第一组样例方案可以是 (1) 1 (4) 6 5 (3) 2 第二组样例方案可以是 1 2 4 (10) 3 (10)
解题思路:网络流,二分答案。可以考虑为有n+1个空位,需要m个物品去填充。如果某个物品可以放在某个位置,就连边,容量为 1。需要额外增加一个节点,如果某个位置可以不放物品,这个节点就和那个位置连边。看看网络最大流是不是为n+1即可。如果是,则说明存在放置的方案
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <functional>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;
#define MAXN 500
struct node
{
int u, v, next, cap;
} edge[MAXN * MAXN];
int nt[MAXN], s[MAXN], d[MAXN], visit[MAXN];
int a[MAXN], b[MAXN];
int cnt, n, m;
void init()
{
cnt = 0;
memset(s, -1, sizeof s);
}
void add(int u, int v, int c)
{
edge[cnt].u = u;
edge[cnt].v = v;
edge[cnt].cap = c;
edge[cnt].next = s[u];
s[u] = cnt++;
edge[cnt].u = v;
edge[cnt].v = u;
edge[cnt].cap = 0;
edge[cnt].next = s[v];
s[v] = cnt++;
}
bool BFS(int ss, int ee)
{
memset(d, 0, sizeof d);
d[ss] = 1;
queue<int>q;
q.push(ss);
while (!q.empty())
{
int pre = q.front();
q.pop();
for (int i = s[pre]; ~i; i = edge[i].next)
{
int v = edge[i].v;
if (edge[i].cap > 0 && !d[v])
{
d[v] = d[pre] + 1;
q.push(v);
}
}
}
return d[ee];
}
int DFS(int x, int exp, int ee)
{
if (x == ee || !exp) return exp;
int temp, flow = 0;
for (int i = nt[x]; ~i; i = edge[i].next, nt[x] = i)
{
int v = edge[i].v;
if (d[v] == d[x] + 1 && (temp = (DFS(v, min(exp, edge[i].cap), ee))) > 0)
{
edge[i].cap -= temp;
edge[i ^ 1].cap += temp;
flow += temp;
exp -= temp;
if (!exp) break;
}
}
if (!flow) d[x] = 0;
return flow;
}
int Dinic_flow(int ss, int ee)
{
int ans = 0;
while (BFS(ss, ee))
{
for (int i = 0; i <= n + m + 3; i++) nt[i] = s[i];
ans += DFS(ss, INF, ee);
}
return ans;
}
int check(int x)
{
init();
add(n + m + 3, 0 + 1 + m, 1);
add(n + m + 3, n + 1 + m, 1);
for (int i = 1; i < n; i++)
if (abs(a[i] - a[i + 1]) <= x)
add(n + m + 3, i + 1 + m, 1);
add(0, n + m + 3, n + 1 - m);
for (int i = 1; i <= m; i++) add(0, i, 1);
for (int i = 1; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
if (j == 0)
{
if (abs(b[i] - a[1]) <= x)
add(i, j + 1 + m, 1);
}
else if (j < n)
{
if (abs(b[i] - a[j]) <= x && abs(b[i] - a[j + 1]) <= x)
add(i, j + 1 + m, 1);
}
else
{
if (abs(b[i] - a[n]) <= x)
add(i, j + 1 + m, 1);
}
}
}
for (int j = 0; j <= n; j++) add(j + 1 + m, n + m + 2, 1);
if (Dinic_flow(0, n + m + 2) == n + 1) return 1;
return 0;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = 1; i <= m; i++) scanf("%d", &b[i]);
int l = 0, r = 1e9, ans;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
printf("%d\n", ans);
}
return 0;
}