Blocks && Fixing the Great wall
读完大概都能发现是dp
方法都很套路
首先第一个题每次取的是一段区间,就能够想到区间dp
按照区间dp的模板能够想到一种裸的方法:
\(dp[i][j]\) 表示处理完 \([i...j]\) 的最大分数
然后你会发现这种方法连样例1都不能搞定
因为 \(dp[i][j]\) 可能受到后面一些同色块的影响,导致直接处理不能获得最优值
那怎么办?
哪有问题就解决哪里
添加一位 \(k\), 表示 区间右还有与块 \(j\) 颜色相同的 \(k\) 个块
怎么转移?
- 直接把 \([j,j+k]\) 这段区间领出来处理分数
- 找到 \(j\) 之前的一个与 \(j\) 颜色相同的块,然后把 \([p+1,j]\) 剖出来,剩下 \([i,p,k+1]\) 接着 \(dp\)
实现可以采用线性或者记忆化
int n, Case ;
int col[N], hd[N], nxt[N] ;
ll dp[N][N][N] ;
ll dfs(int i, int j, int k) {
if (i > j) return 0 ;
if (dp[i][j][k] >= 0) return dp[i][j][k] ;
ll& ans = dp[i][j][k] ;
ans = dfs(i, j - 1, 0) + (k + 1) * (k + 1) ;
for (int p = nxt[j]; p >= i; p = nxt[p])
chmax(ans, dfs(i, p, k + 1) + dfs(p + 1, j - 1, 0)) ;
return ans ;
}
signed main() {
int T ; scanf("%d", &T) ;
while (T--) {
ass(dp, -1) ; clr(nxt) ; clr(hd) ;
scanf("%d", &n) ;
rep(i, 1, n) {
scanf("%d", &col[i]) ;
nxt[i] = hd[col[i]] ;
hd[col[i]] = i ;
}
printf("Case %d: %lld\n", ++Case, dfs(1, n, 0)) ;
}
return 0 ;
}
第二个题就更套路了,我怎么记得我做过这个题
好像是关路灯吧我也忘记了
有一个结论是,把这些缺口排成一排,不可能先走过这个点不修走过去,然后又走回来修,这样肯定是不优的
换句话说,就是修的段肯定是一个连续的区间
配合数据范围提示能够想到区间 \(dp\)
\(dp[i][j][0/1]\) 表示 当前处理了区间 \([i...j]\),当前在 \(i\) 或 \(j\) 的 方案数的最小代价
\(dp[l][r][0]=min(dp[l-1][r][0]+len(l-1,l)/v*cost, dp[l][r+1][1]+len(l,r+1)/v*cost)\)
\(dp[l][r][1]=min(dp[l-1][l][0]+len(l-1,r)/v*cost, dp[l][r+1][1]+len(r,r+1)/v*cost)\)
\(cost\) 就是这一段走的代价,可以通过前缀和处理
注意将开始节点也塞进去,\(n+1\) 个点进行 $dp $
orz you
struct node {
double pos, c, del ;
bool operator < (const node &a) const {
return pos < a.pos ;
}
} a[N] ;
int n, v, x ;
double sum[N], dp[N][N][2] ;
double dfs(int ll, int rr, int d) {
if (ll == 1 && rr == n + 1) return 0 ;
if (dp[ll][rr][d] != iinf) return dp[ll][rr][d] ;
double resl = 0, resr = 0, w = sum[n + 1] - (sum[rr] - sum[ll - 1]) ;
if (ll > 1) {
if (d == 1) resl = (a[rr].pos - a[ll - 1].pos) / v * w ;
else resl = (a[ll].pos - a[ll - 1].pos) / v * w ;
}
if (rr <= n) {
if (d == 1) resr = (a[rr + 1].pos - a[rr].pos) / v * w ;
else resr = (a[rr + 1].pos - a[ll].pos) / v * w ;
}
if (ll > 1) chmin(dp[ll][rr][d], dfs(ll - 1, rr, 0) + resl) ;
if (rr <= n) chmin(dp[ll][rr][d], dfs(ll, rr + 1, 1) + resr) ;
return dp[ll][rr][d] ;
}
int main() {
while (scanf("%d%d%d", &n, &v, &x) != EOF && n && v && x) {
double ssum = 0 ;
rep(i, 1, n) scanf("%lf%lf%lf", &a[i].pos, &a[i].c, &a[i].del) ;
a[n + 1] = (node) {x, 0, 0} ;
sort(a + 1, a + n + 2) ;
rep(i, 1, n + 1) ssum += a[i].c, sum[i] = sum[i - 1] + a[i].del ;
rep(i, 1, n + 1)
rep(j, 1, n + 1)
dp[i][j][0] = dp[i][j][1] = iinf ;
rep(i, 1, n + 1)
if (a[i].pos == x) {
printf("%.0lf\n", floor(dfs(i, i, 0) + ssum)) ;
break ;
}
}
return 0 ;
}
加油ヾ(◍°∇°◍)ノ゙