BottomCoder SRM 394 div2

SRM 394 div2

points result time
250 AC 4.5
500 AC 20.5
1000 MLE(ダメもとsubmit)

カラフルだった今回。発想力を問う問題でまくり。

250

各マスに高さ(0〜9)が指定されているマップareaMap(<=50*50)がある。(0,0)からはじめて、次の操作を、もうできなくなるまでに行うときの回数を求めよ。

(i,j)にいるとき(i+1, j), (i, j-1), (i-1, j), (i, j+1)の順に探索する。探索先がマップの中にあって、一度も訪れたことがなくて、(i,j)との高低差がheightDifference以下のときにそこに移動する。

実装ゲー。操作の指示通りに書きます。

import java.util.Arrays;

public class MountainWalk {
	public int cellsVisited(String[] areaMap, int heightDifference) {
		int n = areaMap.length;
		int m = areaMap[0].length();
		char[][] map = new char[n][m];
		for(int i = 0;i < n;i++)map[i] = areaMap[i].toCharArray();
		boolean[][] visited = new boolean[n][m];
		int r = 0, c = 0;
		int[] dr = {1, 0, -1, 0};
		int[] dc = {0, -1, 0, 1};
		int step = 0;
		outer:
		while(true){
			visited[r][c] = true;
			step++;
			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 && !visited[nr][nc] && Math.abs(map[r][c] - map[nr][nc]) <= heightDifference){
					r = nr;
					c = nc;
					continue outer;
				}
			}
			break;
		}
		return step;
		
	}

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

500

小文字だけからなる文字列s(||<=50)が与えられる。ここから最大n文字削って、同じ文字の最多文字数-同じ文字の最少文字数(0は含まない)を最小にしたい。最小値を求めよ。

貪欲かなーDPかなーとか考えたけど、書きかけるとどうもしっくりこない・・というところでひらめいた。
問われているのは最多文字数と最少文字数なので、たとえば最多文字数をAにしたとき、これを実現するためにはAより多いの文字数になっているものを削ってAにすれば良い。同様に、最少文字数をBにしたとき、B未満の文字数になっているものを削って0にすれば良い。
そうして、各A,Bについて実現するための削除文字数がわかるので、全走査して、削除文字数がn以下でかつ差が最小であるものを選べば良い。

import java.util.Arrays;

public class RoughStrings {
	public int minRoughness(String s, int n) {
		int m = s.length();
		int[] ct = new int[26];
		for(int i = 0;i < m;i++){
			ct[s.charAt(i)-'a']++;
		}
		
		int[] tmax = new int[m+1];
		for(int i = 1;i <= m;i++){
			int sum = 0;
			for(int j = 0;j < 26;j++){
				if(ct[j] >= i){
					sum += ct[j] - i;
				}
			}
			tmax[i] = sum;
		}
		
		int[] tmin = new int[m+1];
		for(int i = 1;i <= m;i++){
			int sum = 0;
			for(int j = 0;j < 26;j++){
				if(ct[j] < i){
					sum += ct[j];
				}
			}
			tmin[i] = sum;
		}
		
		int min = 9999;
		for(int i = 1;i <= m;i++){
			for(int j = 1;j <= i;j++){
				if(min > i - j && tmax[i] + tmin[j] <= n){
					min = i - j;
				}
			}
		}
		return min;
	}

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

1000

整数xに対し、d(x)=#{k|1<=k

import java.util.Arrays;

public class ProperDivisors {
	// k<m, k|m, k^n!|m
	public int analyzeInterval(int a, int b, int n) {
		int ct = 0;
		for(int i = 1;i <= a+b;i++){
			ct += (a+b)/i-(a-1)/i;
		}
		ct -= (b+1);
		for(int p = 1;;p++){
			long q = 1;
			for(int i = 0;i < n;i++)q *= p;
			if(q > a+b)break;
			ct -= (a+b)/q-(a-1)/q;
		}
		if(a == 1)ct++;
		
		return ct;
	}
	
	void tr(Object... o) { System.out.println(Arrays.deepToString(o)); }
}

こっちはやけくそ提出版。最大ケースで手元で2.9s近くかかっていた。約数を篩っぽくだすがあえなくMLE.

import java.util.Arrays;
import java.util.BitSet;

public class CopyOfProperDivisors {
	// k<m, k|m, k^n!|m
	public int analyzeInterval(int a, int b, int n) {
		b += a;
		int ct = b - a + 1;
		for(int p = 2;;p++){
			int q = 1;
			for(int i = 0;i < n;i++)q *= p;
			if(q > b)break;
			int sup = b - b%q;
			int inf = a - a%q;
			if(inf < a)inf += q;
			ct += (sup - inf) / q + 1;
		}
		
		int[] u = new int[b+1];
		int[] r = new int[b+1];
		Arrays.fill(r,a,b+1,1);
		for(int i = a;i <= b;i++){
			u[i] = i;
		}
		
		int[] primes = sieveEratosthenes((int)Math.sqrt(b));
		
		for(int p : primes){
			int f = a - a%p;
			if(f < a)f += p;
			for(int i = f;i <= b;i+=p){
				int c = 0;
				for(;u[i] % p == 0;u[i] /= p, c++);
				if(c > 0){
					r[i] *= c+1;
				}
			}
		}
		
		int all = -ct;
		for(int i = a;i <= b;i++){
			if(u[i] > 1){
				all += r[i] * 2 - 1;
			}else{
				all += r[i] - 1;
			}
		}
		if(a == 1)all++;
		
		return all;
	}
	
	public static int[] sieveEratosthenes(int n)
	{
		int[] ret = new int[(int)(n / Math.log(n)) + (int)(n / (Math.log(n)*Math.log(n))*1.5)  ];
		ret[0] = 2;
		int pos = 1;
		
		// 0:3 1:5
		// 2x+3=n
		BitSet bs = new BitSet(n/2+1);
		int sup = (n - 3) / 2;
		for(int i = bs.nextClearBit(0);i <= sup; i = bs.nextClearBit(i+1)){
			int p = 2 * i + 3;
			ret[pos++] = p;
			for(int j = i + p;j <= sup;j += p){
				bs.set(j);
			}
		}
		
		int[] res = new int[pos];
		for(int i = 0;i < pos;i++)res[i] = ret[i];
		return res;
	}
	
	void tr(Object... o) { System.out.println(Arrays.deepToString(o)); }
}