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


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