BottomCoder SRM 374 div2

SRM 374 div2

points result time
250 AC 4.2m
500 AC 12.5m
1000 AC 25m

hack祭り。問題文が長い割に中身がなかった・・

250

x,y(<=100)からwidth,height(<=100, height:偶数)だけ広がった長方形の(x,y+height/2), (x+width, y+height/2)それぞれを中心に、長方形の外側に向けてheight/2の半円がある。与えられた点のうち、これらの図形の境界上か内部にあるものの個数を求めよ。

前フリが壮大な割に訊きたいことはこれだけだったという。長方形、円についてそれぞれ判定すればよい。制約も小さいので、すべてintの範囲でもOK.

import java.util.Arrays;

public class HockeyFault {
	public int numPlayers(int width, int height, int x, int y, int[] px, int[] py) {
		int ct = 0;
		for(int i = 0;i < px.length;i++){
			int xx = px[i];
			int yy = py[i];
			if(xx >= x && xx <= x + width && yy >= y && yy <= y + height){
				ct++;
				continue;
			}
			if((xx - x) * (xx - x) + (yy-(y+height/2))*(yy-(y+height/2)) <= (height/2)*(height/2)){
				ct++;
				continue;
			}
			if((xx - (x+width)) * (xx - (x+width)) + (yy-(y+height/2))*(yy-(y+height/2)) <= (height/2)*(height/2)){
				ct++;
				continue;
			}
		}
		return ct;
	}

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

500

与えられた文字列配列(||<=50)を次の順番にソートせよ。ただし文字列は子音ではじまり母音で終わる。
文字列を、連続した(子音1個以上+母音1個以上)の配列に分割し、ソートしたもの、を比べる。
上記が等しい場合は、連続した(子音1個以上+母音1個以上)の配列のソートしていないものを比べる。

まず配列への分割は、"母音,子音"の順になっているところを見つけて順次切り出せば良い。あらかじめ文字列の末尾に子音を追加しておけば多少楽になる。
配列を切り出した後は、ソートしたものとしていないものをつくっておけば、あとは比較関数を適当にかくだけ。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SyllableSorting {
	public String[] sortWords(String[] words) {
		int n = words.length;
		final List<List<String>> l = new ArrayList<List<String>>();
		final List<List<String>> sl = new ArrayList<List<String>>();
		for(int i = 0;i < n;i++){
			words[i] += " ";
			List<String> lo = new ArrayList<String>();
			int prev = 0;
			for(int j = 0;j < words[i].length()-1;j++){
				char c = words[i].charAt(j);
				char cn = words[i].charAt(j+1);
				if(!consonant(c) && consonant(cn)){
					lo.add(words[i].substring(prev, j+1));
					prev = j+1;
				}
			}
			words[i] = words[i].substring(0, words[i].length() - 1);
			l.add(lo);
			List<String> loo = new ArrayList<String>(lo);
			Collections.sort(loo);
			sl.add(loo);
		}
		
		Integer[] ord = new Integer[n];
		for(int i = 0;i < n;i++){
			ord[i] = i;
		}
		Arrays.sort(ord, new Comparator<Integer>(){
			public int compare(Integer x, Integer y)
			{
				for(int i = 0;i < sl.get(x).size() && i < sl.get(y).size();i++){
					if(!sl.get(x).get(i).equals(sl.get(y).get(i))){
						return sl.get(x).get(i).compareTo(sl.get(y).get(i));
					}
				}
				if(l.get(x).size() - l.get(y).size() != 0){
					return l.get(x).size() - l.get(y).size();
				}
				for(int i = 0;i < l.get(x).size() && i < l.get(y).size();i++){
					if(!l.get(x).get(i).equals(l.get(y).get(i))){
						return l.get(x).get(i).compareTo(l.get(y).get(i));
					}
				}
				return 0;
			}
		});
		
		String[] ret = new String[n];
		for(int i = 0;i < n;i++){
			ret[i] = words[ord[i]];
		}
		
		return ret;
	}
	
	boolean consonant(char c)
	{
		return !(c == 'a' || c == 'i' || c == 'u' || c == 'e' || c == 'o');
	}

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

1000

文字列の2次元配列photo(<=50*50)が与えられる。これのi行j列目に文字kがあるというのは、各辺がx,y軸に平行な四角形(2j,2i)-(2j+2,2i+2)の範囲に文字kがある、という認識で。このとき辺が隣接している四角形の連結成分で、面積がthreshold以上になるものを選んで、その連結成分を覆う、各辺がx,y軸に平行な最小の長方形の中心の座標をx,y座標昇順に列挙して返せ。

という問題の意味を理解するまでにかなりの時間を要した。わかればなんてことはない。ただのBFSで連結成分を拾って色々調べるだけだった。覆う長方形の中心も、x,y座標それぞれについて(最小座標+最大座標)/2で求められる。
最後に返す"x y"は"列 行"なことに注意。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class PlayerExtraction {
	public String[] extractPlayers(String[] photo, int k, int threshold) {
		int n = photo.length;
		int m = photo[0].length();
		char[][] p = new char[n][m];
		for(int i = 0;i < n;i++){
			p[i] = photo[i].toCharArray();
		}
		
		List<Integer> ll = new ArrayList<Integer>();
		for(int i = 0;i < n;i++){
			for(int j = 0;j < m;j++){
				if(p[i][j] == k+'0'){
					Queue<Integer> q = new LinkedList<Integer>();
					q.add(i*m+j);
					int S = 0;
					int minr = i, maxr = i+1;
					int minc = j, maxc = j+1;
					p[i][j] = ' ';
					int[] dr = {1,0,-1,0};
					int[] dc = {0,1,0,-1};
					while(!q.isEmpty()){
						int cur = q.poll();
						int r = cur/m;
						int c = cur%m;
						minr = Math.min(minr, r);
						minc = Math.min(minc, c);
						maxr = Math.max(maxr, r+1);
						maxc = Math.max(maxc, c+1);
						S++;
						for(int l = 0;l < 4;l++){
							int nr = r+dr[l];
							int nc = c + dc[l];
							if(nr >= 0 && nr < n && nc >= 0 && nc < m && p[nr][nc] == k+'0'){
								p[nr][nc] = ' ';
								q.add(nr*m+nc);
							}
						}
					}
					if(4*S >= threshold){
						ll.add((minc+maxc)*2*n+(minr+maxr));
					}
				}
			}
		}
		Collections.sort(ll);
		String[] ret = new String[ll.size()];
		for(int i = 0;i < ll.size();i++){
			int cur = ll.get(i);
			int rr = cur % (2*n);
			int cc = cur / (2*n);
			ret[i] = cc + " " + rr;
		}
		
		return ret;
	}

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