zxa and wifi
zxa来到Q镇做义工,镇长希望给住在Q镇中轴线上的n户人家实现网络覆盖。这n户人家可以看作是中轴线上的质点,从东到西依次编号从1到n,其中第i(1≤i<n)户人家到第(i+1)户人家的距离为di。 zxa负责了这个项目的方案设计,他获悉运营商给出了两种架设网络的方式。一种是花费ai的费用在第i(1≤i≤n)户人家安装无线路由器和相关网线使得距离第i户人家不超过ri的人家(包括第i户人家)都能上网。另一种是花费bi的费用为第i(1≤i≤n)户人家接通光缆使得该户人家能上网。 zxa很好奇,如果镇上为了防止无线电的辐射过大而至多只能在k户人家架设无线路由,那么使得这n户人家都能上网的最小花费是多少,你能帮助他吗?
第一行有一个正整数T,表示有T组数据。 对于每组数据: 第一行有两个整数n和k。 第二行有(n−1)个正整数,表示d1,d2,⋯,dn−1。 接下来n行,第i(1≤i≤n)行有三个正整数ai,ri和bi。 每一行相邻数字之间只有一个空格。 1≤T≤100,2≤n≤2⋅104,1≤k≤min(n,100),1≤ai,bi,di,ri≤105,1≤∑n≤105
对于每组数据,输出一行,包含一个正整数,表示使得这n户人家都能上网的最小花费。
2 2 1 1 12 11 3 1 7 4 5 5 7 4 8 6 13 6 3 14 2 3 3 6 4 11 12 2 9 14 4
1 12
对于第二组样例,zxa在3号人家安装无线路由器,在1号、4号、5号人家接通光缆,这样的总代价是3+3+2+4=12。
首先二分得到每一个路由器作用的范围。
dp[i][k]表示使用k个路由器覆盖前i个点所需要的最小代价。
不使用路由器覆盖第i个点的话,有 dp[i][k]=dp[i][k-1]+b[i]
如果使用路由器覆盖第i个点,则直接枚举路由器那些端点在第i个点,然后找dp[le[id]][k-1]到dp[i][k-1]的最小值,使用一个队列维护这个最小值,二分查找。
代码:
#pragma warning(disable:4996)
#include <fstream>
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define INF 0x33ffffff
#define mem(a, b) memset(a, b, sizeof(a))
#define pper(i,n,m) for(int i = n;i >= m; i--)
#define repp(i, n, m) for (int i = n; i <= m; i++)
#define rep(i, n, m) for (int i = n; i < m; i++)
#define sa(n) scanf("%d", &(n))
#define mp make_pair
#define ff first
#define ss second
#define pb push_back
const int maxn = 5e4 + 5;
const ll mod = 1e9 + 7;
const double PI = acos(-1.0);
struct ed
{
int to;
int next;
}edge[maxn];
int n, kth, edgen;
int a[maxn], r[maxn], b[maxn], d[maxn];
int head[maxn], que[maxn], le[maxn], ri[maxn], dp[maxn][110];
void add(int u, int v)
{
edgen++;
edge[edgen].to = v;
edge[edgen].next = head[u];
head[u] = edgen;
}
void init()
{
edgen = 0;
memset(head, -1, sizeof(head));
memset(edge, -1, sizeof(edge));
}
void solve()
{
int i, j, k, h;
sa(n), sa(kth);
repp(i, 2, n)
{
sa(d[i]);
d[i] = d[i - 1] + d[i];
}
repp(i, 1, n)
{
sa(a[i]), sa(r[i]), sa(b[i]);
}
repp(i, 1, n)
{
int pos1 = lower_bound(d + 1, d + n + 1, d[i] - r[i]) - d;
int pos2 = lower_bound(d + 1, d + n + 1, d[i] + r[i]) - (d + 1);
le[i] = pos1, ri[i] = pos2;
add(ri[i], i);
}
dp[0][0] = 0;
for (i = 1; i <= n; i++)
{
dp[i][0] = dp[i - 1][0] + b[i];
}
int res = dp[n][0];
for (k = 1; k <= kth; k++)
{
int t = 1;
que[t] = 0;
for (i = 1; i <= n; i++)
{
dp[i][k] = dp[i - 1][k] + b[i];
for (h = head[i]; h != -1; h = edge[h].next)
{
int to = edge[h].to;
int pos = lower_bound(que + 1, que + t + 1, le[to] - 1) - que;
if (pos == t + 1)
continue;
dp[i][k] = min(dp[i][k], dp[que[pos]][k - 1] + a[to]);
}
while (t > 1 && dp[que[t]][k - 1] >= dp[i][k - 1])
{
t--;
}
t++;
que[t] = i;
}
res = min(res, dp[n][k]);
}
printf("%d\n", res);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("i.txt", "r", stdin);
freopen("o.txt", "w", stdout);
#endif
int t;
sa(t);
while (t--)
{
init();
solve();
}
return 0;
}