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;
}