您的位置:首页 > 其它

hdu5681 zxa and wifi

2016-05-31 22:11 465 查看
这道题目是不太好想的,尽管很容易看出来应该是dp,但是状态转移总觉得无从下手。

其实我们可以将状态分层,比如设$dp(i, j)$为用$i$个路由器覆盖前$j$个点所需的最小代价

我们先不考虑状态,而是考虑在每个位置上的决策对状态的影响,考虑在位置j的决策

1.如果在此处放置网线,有$dp(i, j) = min(dp(i, j), dp(i, j - 1) + b(i))$

2.如果在此处放置路由器,有$dp(i, r(j)) = min(dp(i, r(j)), dp(i - 1, l(j) - 1) + a(i))$

当然此处可以什么都不放,但是这种决策对状态没有影响,因此我们不考虑它。

$[l(i), r(i)]$表示$i$位置路由器的覆盖区间

注意到固定$i$,$dp(i, j)$应该是非降的,因此条件2的更新应该适用于所有$dp(i, k): k \leq r(j)$

用两重循环依次计算状态,用stl中的vector储存i位置满足$r(k) = i$的所有$k$,先用式2从后往前更新,再用式1从前往后更新即可

复杂度$O(n * max(k, log(n))$

代码如下:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <set>
#include <ctime>
#include <iostream>
using namespace std;
typedef long long ll;
const int int_inf = 0x3f3f3f3f;
const ll ll_inf = (ll)1 << 62;
const int mod = 1e9 + 7;
const double double_inf = 1e30;
typedef unsigned long long ul;
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define mp make_pair
#define st first
#define nd second
#define lson (u << 1)
#define rson (u << 1 | 1)
#define pii pair<int, int>
#define pb push_back
#define type(x) __typeof(x.begin())
#define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++)
#define FOR(i, s, t) for(int i = s; i <= t; i++)
#define ROF(i, t, s) for(int i = t; i >= s; i--)
#define dbg(x) cout << x << endl
#define dbg2(x, y) cout << x << " " << y << endl
#define clr(x, i) memset(x, (i), sizeof(x))
#define maximize(x, y) x = max((x), (y))
#define minimize(x, y) x = min((x), (y))
inline int readint(){
bool neg = 0; char ch, t[11];
int k = 0;
while((ch = getchar()) == ' ' || ch == '\n') ;
neg = ch == '-';
ch == '-' ? neg = 1 : t[k++] = ch;
while((ch = getchar()) >= '0' && ch <= '9') t[k++] = ch;
int x = 0, y = 1;
while(k) x += (t[--k] - '0') * y, y *= 10;
return neg ? -x : x;
}

inline int readstr(char *s){
char ch;
int len = 0;
while((ch = getchar()) == ' ' || ch == '\n') ;
*(s++) = ch, ++len;
while((ch = getchar()) != ' ' && ch != '\n') *(s++) = ch, ++len;
*s = '\0';
return len;
}
inline void writestr(const char *s){
while(*s != '\0') putchar(*(s++));
putchar('\n');
}

inline int add(int x, int y){
if(x < 0) x += mod;
if(y < 0) y += mod;
return (x + y) % mod;
}

inline int mult(int x, int y){
if(x < 0) x += mod;
if(y < 0) y += mod;
ll tem = (ll)x * y;
return tem % mod;
}

int debug = 0;
//-------------------------------------------------------------------------
const int maxn = 2e4 + 10;
int a[maxn], x[maxn], b[maxn], d[maxn];
ll dp[105][maxn];
vector<int> c[maxn];
int l[maxn], r[maxn];
int n, k;
//-------------------------------------------------------------------------

ll solve(){
d[0] = d[1] = 0;
FOR(i, 2, n) d[i] += d[i - 1];
FOR(i, 0, maxn - 1) c[i].clear();
FOR(i, 1, n){
int len = x[i];
int L = 0, R = i;
while(R - L > 1){
int mid = (R + L) >> 1;
if(d[i] - d[mid] <= len) R = mid;
else L = mid;
}
l[i] = R;
L = i, R = n + 1;
while(R - L > 1){
int mid = (R + L) >> 1;
if(d[mid] - d[i] <= len) L = mid;
else R = mid;
}
r[i] = L;
c[L].pb(i);
}
dp[0][0] = 0;
FOR(i, 1, n) dp[0][i] = dp[0][i - 1] + b[i];
FOR(i, 1, k){
dp[i][n + 1] = ll_inf;
ROF(j, n, 1){
int sz = c[j].size();
dp[i][j] = dp[i][j + 1];
FOR(u, 0, sz - 1) minimize(dp[i][j], dp[i - 1][l[c[j][u]] - 1] + a[c[j][u]]);
}
dp[i][0] = 0;
FOR(j, 1, n) minimize(dp[i][j], dp[i][j - 1] + b[j]);
}
ll ans = dp[0]
;
FOR(i, 1, k) minimize(ans, dp[i]
);
return ans;
}

int main(){
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(debug) freopen("in.txt", "r", stdin);
int T = readint();
while(T--){
n = readint();
k = readint();
FOR(i, 1, n - 1) d[i + 1] = readint();
FOR(i, 1, n) a[i] = readint(), x[i] = readint(), b[i] = readint();
ll ans = solve();
printf("%lld\n", ans);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: