BottomCoder SRM 398 div2

SRM 398 div2

point result time
250 AC 2m
500 AC 7m
900 AC 9.5m

@chokudai氏がきていて無駄に緊張した。

250

整数A,X,Y,M(1<=*<=10000),n(2<=*<=10000)が与えられ、数列Aが
A[0] = A0
A[i] = (A[i - 1] * X + Y) MOD M, for 0 < i < n
で定義される。Aの任意の2項の差の絶対値の最小値を求めよ。

数列をつくってからソートして、そのうちの隣接する2項の差の絶対値をとっていって最小値を出力すればよい。MOD前の()でもintの範囲をこえないのですべてintでOK.

import java.util.Arrays;

public class MinDifference {

	public int closestElements(int A0, int X, int Y, int M, int n) {
		int[] a = new int[n];
		a[0] = A0;
		for(int i = 1;i < n;i++){
			a[i] = (a[i-1] * X + Y) % M;
		}
		Arrays.sort(a);
		
		int min = 9999999;
		for(int i = 0;i < n - 1;i++){
			min = Math.min(min, a[i+1] - a[i]);
		}
		return min;
	}

}

500

2つの数x,y(||<=100, x!=y)を2回ずつ使い、各数字の間にそれぞれ+-*のどれかを置いて数式をつくる。できあがった数式のうち、前から計算(演算子の優先順位は無視)してval(||<=10^8)と等しくなるような数式の個数はいくつか。

数字の置き方は6通り、演算子の置き方は3^3通りなので全探索でOK.さらに、6,3,3,3通りは独立なので、4重forでいける。演算を1個の関数にまとめておけば楽に書けるかな?

public class CountExpressions {

	public int calcExpressions(int x, int y, int val) {
		int ct = 0;
		for(int i = 0;i < 16;i++){
			if(Integer.bitCount(i) == 2){
				int[] v = new int[4];
				for(int j = 0;j < 4;j++){
					v[j] = (i>>j)%2 == 0 ? x : y;
				}
				long ret = v[0];
				for(int a = 0;a < 3;a++){
					long ret2 = cal(a, ret, v[1]);
					
					for(int b = 0;b < 3;b++){
						long ret3 = cal(b, ret2, v[2]);
						for(int c = 0;c < 3;c++){
							long ret4 = cal(c, ret3, v[3]);
							if(ret4 == val){
								ct++;
							}
						}
					}
				}
			}
		}
		return ct;
	}
	
	long cal(int k, long a, long b)
	{
		if(k == 0){
			return a + b;
		}else if(k == 1){
			return a - b;
		}else if(k == 2){
			return a * b;
		}
		return 0;
	}

}

900

文字列配列matchWords(||<=50, 文字列の長さ<=50)と、この要素数と長さが等しい文字列matchStringが与えられる。文字列配列をこの順に並べていくつかの文字列を右にずらして、どこかの位置に、縦にmatchStringができあがるようにしたい。ずらす文字数の合計の最小値を求めよ。出来上がらない場合は-1を返せ。

サンプルをみると題意が一発でわかる問題。
各文字列matchWords[i]でmatchString[i]と一致する文字の出現位置を列挙しておく。出現しない場合は-1を返す。
列挙したあと、matchStringがそろうindexは高々50-1なので、そろうindexについて走査。各matchWordsについてindex以下の最大の出現位置を求めて、最小ずらし数を計算。これを合計したものを最小化すればよい。オーダーは、列挙したものがソートされているのでO(N^2 log N)でいける。
Arrays.binarySearchのインデックス指定版を最初使っていたのだが、これがJDK1.5にはなかったようで焦った。配列全体版はある。

そろうindexは多分一致する文字の出現位置のどれかになると思うけど、今回は関係なかった。

import java.util.Arrays;

public class MatchString {

	public int placeWords(String matchString, String[] matchWords) {
		int n = matchWords.length;
		int[][] mind = new int[n][];
		int[] p = new int[n];
		for(int i = 0;i < n;i++){
			int[] mr = new int[50];
			for(int j = 0;j < matchWords[i].length();j++){
				if(matchWords[i].charAt(j) == matchString.charAt(i)){
					mr[p[i]++] = j;
				}
			}
			if(p[i] == 0){
				return -1;
			}
			mind[i] = new int[p[i]];
			for(int j = 0;j < p[i];j++){
				mind[i][j] = mr[j];
			}
		}
		
		int min = 99999999;
		outer:
		for(int i = 0;i < 101;i++){
			int s = 0;
			for(int j = 0;j < n;j++){
				int ind = Arrays.binarySearch(mind[j], i);
				if(ind < 0){
					ind = -ind - 2;
					if(ind < 0)continue outer;
					s += i - mind[j][ind];
				}
			}
			min = Math.min(min, s);
		}
		if(min == 99999999)return -1;
		return min;
	}

}