BottomCoder SRM 383 div2
points | result | time |
---|---|---|
250 | AC | 3m |
500 | AC | 8.4m |
1000 | AC | 15m |
ちょい易し目でした。
250
マップ(||<=50*50)上の'-'が横に連続したかたまりと'|'が縦に連続したかたまりの合計個数を求めよ。
この間のSRM496div1easyとすごく似てる。というかほとんど同じ。
すべてのセルについて走査。'-'だったら、左隣が'-'でなければカウント++, '|'だったら、上隣が'|'でなければカウント++, とすれば良い。
public class FloorLayout { public int countBoards(String[] layout) { int n = layout.length; int m = layout[0].length(); int ct = 0; for(int i = 0;i < n;i++){ for(int j = 0;j < m;j++){ if(layout[i].charAt(j) == '-'){ if(j == 0 || layout[i].charAt(j-1) != '-'){ ct++; } }else{ if(i == 0 || layout[i-1].charAt(j) != '|'){ ct++; } } } } return ct; } }
500
N(<=50)個の長さlengths[*](<=10000)木の棒が与えられる。これをある長さになるようにそろえて切って売る(1つの木の棒から何個でも切り出せる)。長さLにそろえたとき、売値はL*(Lの長さの断片の個数)*woodValueとなる。また、1回切るためにcostPerCutだけかかる。このとき、売値-コストの最大値を求めよ。
最後のサンプルがなければ死んでいるところだった。
Lを全走査。(Lの長さの断片の個数)=\sum [lengths[*]/L]で与えられる。また、切り出す回数は、[lengths[*]/L]から、棒の長さがLの倍数なら1節約できるので、(切り出す合計回数)=\sum [(lengths[*]-1)/L]となる。これで売値-コストを計算して最大化すればよい。
public class Planks { public int makeSimilar(int[] lengths, int costPerCut, int woodValue) { int max = 0; for(int i = 1;i <= 10000;i++){ int cost = 0; for(int len : lengths){ cost += Math.max(0, -(len-1)/i * costPerCut + len/i*i*woodValue); } max = Math.max(max, cost); } return max; } }
1000
N*M(<=25*25)の地図が与えられる。それぞれのセルは高さが0〜51となっている。(0,0)から出発して、隣のセルに移動して適当にまわって時間timeToDark以内に(0,0)に戻ってくる事を考える。隣のセルとの高低差の絶対値がthresholdより大きい場合は移動できない。高低差が+1以上の時は(高低差)^2の時間がかかり、それ以外のときは1だけ時間がかかる。このとき行けるセルの最大の高さを求めよ。
1セル1回縛りとかもないので、実はそんなに難しくない問題。
あるセルCについて、(0,0)とCとの最短往路と最短復路の合計がtimeToDark以内であればCに行けることになる。このようなCのうちの最高点を求めれば良い。
これを達するためには、(0,0)と全点との最短往路と最短復路を求めれば良い。最短往路は、dijkstraで行けるところまで網羅すればOK. 最短復路も、復路を逆行するようにdijkstraを構成すればよい。高低差が-1以下のとき2乗の時間がかかるように、それ以外は1の時間とする。これでO((NM)^2)でできる。
dijkstraのコードさえ用意しておけば、ほとんどコピペでできちゃったりする。
import java.util.Arrays; import java.util.Comparator; import java.util.TreeSet; public class HillWalker { public int highestPoint(String[] landscape, int threshold, int timeToDark) { int n = landscape.length; int m = landscape[0].length(); int[][] h = new int[n][m]; for(int i = 0;i < n;i++){ for(int j = 0;j < m;j++){ char c = landscape[i].charAt(j); if(c <= 'Z'){ h[i][j] = c - 'A'; }else{ h[i][j] = c - 'a' + 26; } } } int[] dr = {1, 0, -1, 0}; int[] dc = {0, 1, 0, -1}; final int[] td = new int[n*m]; Arrays.fill(td, Integer.MAX_VALUE / 3); { TreeSet<Integer> q = new TreeSet<Integer>(new Comparator<Integer>(){ public int compare(Integer a, Integer b) { if(td[a] - td[b] != 0)return td[a] - td[b]; return a - b; } }); q.add(0); td[0] = 0; while(q.size() > 0){ int cur = q.first(); q.remove(cur); int r = cur / m; int c = cur % m; for(int i = 0;i < 4;i++){ int nr = r + dr[i]; int nc = c + dc[i]; if(nr >= 0 && nr < n && nc >= 0 && nc < m){ int dh = h[nr][nc] - h[r][c]; if(dh <= threshold){ int nd = td[cur] + (dh >= 1 ? dh * dh : 1); int x = nr * m + nc; if(nd < td[x]){ q.remove(x); td[x] = nd; q.add(x); } } } } } } final int[] rd = new int[n*m]; Arrays.fill(rd, Integer.MAX_VALUE / 3); { TreeSet<Integer> q = new TreeSet<Integer>(new Comparator<Integer>(){ public int compare(Integer a, Integer b) { if(rd[a] - rd[b] != 0)return rd[a] - rd[b]; return a - b; } }); q.add(0); rd[0] = 0; while(q.size() > 0){ int cur = q.first(); q.remove(cur); int r = cur / m; int c = cur % m; for(int i = 0;i < 4;i++){ int nr = r + dr[i]; int nc = c + dc[i]; if(nr >= 0 && nr < n && nc >= 0 && nc < m){ int dh = h[nr][nc] - h[r][c]; if(dh <= threshold){ int nd = rd[cur] + (dh <= -1 ? dh * dh : 1); int x = nr * m + nc; if(nd < rd[x]){ q.remove(x); rd[x] = nd; q.add(x); } } } } } } int maxh = 0; for(int i = 0;i < n*m;i++){ if(td[i] + rd[i] <= timeToDark && maxh < h[i/m][i%m]){ maxh = h[i/m][i%m]; } } return maxh; } }