BottomCoder SRM 389 div2

SRM 389 div2

points result time
250 AC 2.5m
500 AC 5.5m
1000 AC 23.5m

あれ・・あっさり・・
全問実装ゲー

250

容量maxWeight(<=10^5)の箱に重さweights[i](0<=||<=50)の本をi昇順に詰めていく。必要な箱の個数を求めよ。

この間順序自由の問題がhardで出たナップサック。だが、ここでは順序が決められているので超簡単。本の数が0と言う場合もあることに注意。

import java.util.Arrays;

public class BoxesOfBooks {

	public int boxes(int[] weights, int maxWeight) {
		if(weights.length == 0)return 0;
		int cur = 0;
		int box = 1;
		for(int i = 0;i < weights.length;i++){
			if(cur + weights[i] > maxWeight){
				cur = 0;
				box++;
			}
			cur += weights[i];
		}
		
		return box;
	}

	void tr(Object... o) { System.out.println(Arrays.deepToString(o)); }
}

500

1/bは次の無限級数で近似できる。
1/b=1/(t-c)=c^0/t^1+c^1/t^2+…
tはb以上の最小の2の累乗とする。この右辺のterms項までの和をとってa/bの近似を求めよ。

式が与えられているのでまさにその通りにやるだけ。下手にt^kを計算しようとかしなければ何も問題はない。

import java.util.Arrays;

public class ApproximateDivision {

	public double quotient(int a, int b, int terms) {
		int t = Integer.highestOneBit(b);
		if(t < b)t *= 2;
		double ret = 0;
		int c = t-b;
		double mul = (double)a / t;
		for(int i = 0;i < terms;i++){
			ret += mul;
			mul *= (double)c / (double)t;
		}
		return ret;
	}

	void tr(Object... o) { System.out.println(Arrays.deepToString(o)); }
}

1000

N(<=6)本の弦があるギターでM(<=N)個の音を同時に弾く。どの弦も必ずどれかの音を弾かなければならず、M個の音のどれも欠けてはならない。弦を抑えるときの難しさを、一番高い位置から一番低い位置をひいたもの+1とする。開放弦でいいときは計算に加味しない。すべて開放弦でいいときは0とする。ギターの開放弦のコードと弾くべき音のコードが与えられたとき、難しさの最小値を求めよ。ただしkオクターブ違う音はすべて同じ音とみなす。

Nが小さすぎるので全探索でOK. M^Nだけまわして、全パターンを列挙し、抑えるべき位置の最小値とそれに12足したものを再帰でみていく。
これでO(6^6*(6+2^6)). 実質O(6^6*6+6!*2^6)で余裕で終わる。

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class GuitarChords {
	int[] ss;
	int[] cc;
	int m, n;
	
	public int stretch(String[] strings, String[] chord) {
		Map<String, Integer> map = new HashMap<String, Integer>();
		String[] T = {"A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"};
		for(int i = 0;i < T.length;i++){
			map.put(T[i], i);
		}
		
		n = strings.length;
		m = chord.length;
		cc = new int[m];
		ss = new int[n];
		for(int i = 0;i < m;i++)cc[i] = map.get(chord[i]);
		for(int i = 0;i < n;i++)ss[i] = map.get(strings[i]);
		int[] ord = new int[n];
		for(int i = 0;i < n;i++)ord[i] = 0;
		do{
			int used = 0;
			for(int u : ord)used |= 1<<u;
			if(used != (1<<m)-1)continue;
			rec(ord, 0, 99, 0);
		}while(inc(ord, m));
		
		return gmin;
	}
	
	int gmin = 999;
	
	void rec(int[] ord, int pos, int min, int max)
	{
		if(pos == n){
			if(max - min < 0){
				gmin = 0;
			}else{
				gmin = Math.min(gmin, max - min + 1);
			}
		}else{
			for(int i = (cc[ord[pos]] - ss[pos] + 12)%12;i <= 24;i+=12){
				if(i == 0){
					rec(ord, pos+1, min, Math.max(max, i));
				}else{
					rec(ord, pos+1, Math.min(min, i), Math.max(max, i));
				}
			}
		}
	}

	public static boolean inc(int[] a, int base)
	{
		int n = a.length;
		int i;
		for(i = n - 1;i >= 0 && a[i] == base - 1;i--);
		if(i == -1)return false;
		
		a[i]++;
		Arrays.fill(a, i + 1, n, 0);
		return true;
	}
	
	void tr(Object... o) { System.out.println(Arrays.deepToString(o)); }
}