HDU 5681:zxa and wifi

zxa and wifi

 
 Accepts: 13
 
 Submissions: 299
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
zxa来到Q镇做义工,镇长希望给住在Q镇中轴线上的nn户人家实现网络覆盖。这nn户人家可以看作是中轴线上的质点,从东到西依次编号从11nn,其中第i(1\leq i < n)i(1i<n)户人家到第(i+1)(i+1)户人家的距离为d_idi。

zxa负责了这个项目的方案设计,他获悉运营商给出了两种架设网络的方式。一种是花费a_iai的费用在第i(1\leq i\leq n)i(1in)户人家安装无线路由器和相关网线使得距离第ii户人家不超过r_iri的人家(包括第ii户人家)都能上网。另一种是花费b_ibi的费用为第i(1\leq i\leq n)i(1in)户人家接通光缆使得该户人家能上网。

zxa很好奇,如果镇上为了防止无线电的辐射过大而至多只能在kk户人家架设无线路由,那么使得这nn户人家都能上网的最小花费是多少,你能帮助他吗?
输入描述
第一行有一个正整数TT,表示有TT组数据。

对于每组数据:

第一行有两个整数nnkk。

第二行有(n-1)(n1)个正整数,表示d_1,d_2,\cdots,d_{n-1}d1,d2,,dn1。

接下来nn行,第i(1\leq i\leq n)i(1in)行有三个正整数a_i,r_iai,rib_ibi。

每一行相邻数字之间只有一个空格。

1\leq T\leq 100,2\leq n\leq 2\cdot10^4,1\leq k\leq\min(n, 100),1\leq a_i,b_i,d_i,r_i\leq 10^5,1\leq\sum{n}\leq10^51T100,2n2104,1kmin(n,100),1ai,bi,di,ri105,1n105
输出描述
对于每组数据,输出一行,包含一个正整数,表示使得这nn户人家都能上网的最小花费。
输入样例
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
Hint
对于第二组样例,zxa在33号人家安装无线路由器,在11号、44号、55号人家接通光缆,这样的总代价是3+3+2+4=123+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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章