BottomCoder SRM 388 div2
points | result | time |
---|---|---|
250 | AC | 2.8m |
500 | AC | 8m |
1000 | AC | 4.8m |
やたら簡単だった今回。撃墜祭り。
最初500をひらいてしまってテンパッた。
250
与えられた数列(||<=50)の、連続した狭義単調増加or減少部分列の最大の長さを求めよ。
規模が小さいので、O(N^2)の方法でも余裕。部分列の頭を選んでできるだけ長く追う。
O(N)でもできる。
import java.util.Arrays; public class MonotoneSequence { public int longestMonotoneSequence(int[] seq) { int n = seq.length; int max = 0; for(int i = 0;i < n;i++){ { int j; for(j = i + 1;j < n;j++){ if(seq[j] - seq[j-1] >= 0){ break; } } max = Math.max(max, j - i); } { int j; for(j = i + 1;j < n;j++){ if(seq[j] - seq[j-1] <= 0){ break; } } max = Math.max(max, j - i); } } return max; } void tr(Object... o) { System.out.println(Arrays.deepToString(o)); } }
500
それぞれの候補者(||<=50)への票数(<=100)が与えられる。自分(0)以外の候補者への投票者に賄賂を送って、自分に投票するようにする。他の候補者よりも得票数が多いと当選になるとき、最低何人に賄賂を送ればよいか。
k(0から昇順で走査)人に賄賂を送るとして、votes[0]+k票よりも他の人の得票数が少なければよいので、votes[0]+k以上になっている票をぜんぶ削る。削った合計がkより小さくなったらそのkが答え。削った票は単調減少なので2分探索も可だが、小さすぎるのでやる必要がない。
テンパって何故か得票数の2分探索で書いてしまった。こっちの方針は2分探索だけでは決まらず少々めんどくなる。
import java.util.Arrays; public class VoteRigging { public int minimumVotes(int[] votes) { for(int i = 0;i < 999;i++){ int self = votes[0] + i; int sum = 0; for(int j = 1;j < votes.length;j++){ if(self <= votes[j]){ sum += votes[j] - self + 1; } } if(i >= sum){ return i; } } return 0; } void tr(Object... o) { System.out.println(Arrays.deepToString(o)); } }
テンパッた結果
import java.util.Arrays; public class VoteRigging { public int minimumVotes(int[] votes) { int start = 0; int end = 100; while(end - start > 1){ int mid = (end+start)/2; int sum = 0; for(int i = 1;i < votes.length;i++){ if(mid < votes[i]){ sum += votes[i] - mid; } } int self = votes[0] + sum; if(self > mid){ start = mid; }else{ end = mid; } } int last = 0; for(int i = 1;i < votes.length;i++){ if(start < votes[i]){ last += votes[i] - start; } } int se = votes[0] + last; return last - Math.max(se - (start+2), 0); } void tr(Object... o) { System.out.println(Arrays.deepToString(o)); } }
1000
k(<=1000)以下の素因数だけからなる数をk-smoothという。N(<=5000000)以下のk-smoothな自然数の個数を求めよ。
kまでの素数を求めて、順にS={1}の各要素に{p, p^2, p^3,...}を掛けていくようなことをすれば良い。最後に|S|を求めればOK.
実装上では、Sをbitで管理して、下からbitが立っているところがあればそれにpをかけたbitを立てることを繰り返すだけでよい。
オーダーは・・pをかけた結果は高々5000000通り(被らない)で、多めに見ても10^7なのでいける。(実際は1200000ぐらいしかまわってない)
import java.util.Arrays; import java.util.BitSet; public class SmoothNumbersHard { public int countSmoothNumbers(int N, int k) { BitSet ps = new BitSet(); BitSet smooth = new BitSet(); ps.set(2, k+1); smooth.set(1); for(int p = 2;p <= k;p++){ if(ps.get(p)){ for(int i = p * 2;i <= k;i += p){ ps.clear(i); } for(int i = smooth.nextSetBit(0);i != -1;i = smooth.nextSetBit(i+1)){ if(i * p <= N){ smooth.set(i * p); }else{ break; } } } } return smooth.cardinality(); } void tr(Object... o) { System.out.println(Arrays.deepToString(o)); } }