2010年9月27日月曜日

TopCoder SRM 483

SRM 483(9/26 1:00~3:00)

今回は,Easyを出来るだけ正確かつ早く解く事を目標としました.

■BestApproximationDiv1(Div1 Easy)

□問題
"0.dddddd"という形の小数numberが与えられる.分母がmaxDen以下の分数d/nとnumberを比較し,小数点以下何桁目まで一致しているかを数える.一致桁数が最も大きい分数を求めよ.但し,答えが複数存在する場合には,分母が小さいものを,分母が等しい場合は,分子の小さいものを出力せよ.

□解法
全探索するとO(maxDen2)となりますが,1≦maxDen≦1000ですので問題ありませんでした.

□コード
import java.util.*;
import java.lang.*;

public class BestApproximationDiv1{
public String findFraction(int maxDen, String number){
int bestD=1, bestN=0;
int maxDigit=0;
for(int d=maxDen;d>=1;d--){
for(int n=d-1;n>=0;n--){
String s=((double)n/d)+"";
if(s.length()==1)
s+=".";
s+="000000";
int digit=1;
for(int i=2;i<number.length()&&i<s.length();i++){
if(number.charAt(i)!=s.charAt(i))
break;
digit++;
}
if(digit>=maxDigit){
bestD=d;
bestN=n;
maxDigit=digit;
}
}
}
return bestN+"/"+bestD+" has "+maxDigit+" exact digits";
}
}


■Challenge
他の人達の回答が結構長くて,読めませんでした.

■Result
○×× 0 -0
190.00p

今回は,HardがMediumよりも簡単という噂が聞こえてきて,Hardを解かなかった事を後悔していましたが,意外や意外,実は難しい問題だったようで,多くの人がSystem Testで落とされていました.

■Rating
1372 -> 1463

結構上がりました.4回連続Rating上昇です.目標のYellowCoderまであと少し….

2010年9月25日土曜日

Codeforces Beta Round #30

Codeforces Beta Round #30 9/25(0:00~2:00)

1週間振り.

■A. Accounting
□問題
3つの整数A,B,n(|A|,|B|≦1000, 1≦n≦10)が与えられる.
AXn=Bとなる整数Xが存在するか判定し,存在する場合はその内の1つの解を求めよ.

□解法
場合分けをきっちりやればOK.

□コード
import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;

public class A{
Scanner sc=new Scanner(System.in);

void run(){
int a=sc.nextInt();
int b=sc.nextInt();
int n=sc.nextInt();
if(a*b>0){
a=Math.abs(a);
b=Math.abs(b);
for(int x=1;; x++){
int c=a*(int)Math.pow(x, n);
if(c==b){
println(""+x);
break;
}else if(c>b){
println("No solution");
break;
}
}
}else if(a*b<0){
if(n%2==0){
println("No solution");
return;
}
a=Math.abs(a);
b=Math.abs(b);
for(int x=1;; x++){
int c=a*(int)Math.pow(x, n);
if(c==b){
println("-"+x);
break;
}else if(c>b){
println("No solution");
break;
}
}
}else{
if(a==0&&b==0){
println("1");
}else if(a==0){
println("No solution");
}else{
println("0");
}
}
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new A().run();
}
}


■B. Codeforces World Finals
□問題
Bobの生年月日(BD.BM.BY)とコンテストの開催年月日(DD.MM.YY)が与えられる.コンテストの開催年月日にはBobが18才以上となっているようにBobの生年月日を並び替える(BD,BM,BYをそれぞれ並び替える)ことは出来るか.

□解法
6通り全ての並び替えに対し,それが生年月日であるか+18才以上になるかという条件チェックをちゃんとやったつもりでしたが,堕ちました.

□コード
自主規制

■C. Shooting Gallery
□問題
n個のターゲットがある.ターゲットiはそれぞれ座標(xi, yi),出現時刻ti,命中率piを持つ.プレイヤーは,任意の位置からスタートできるが,座標ciからcjへ移動するのには,|cj-ci|だけの時間がかかる.最適な行動をとった時,ターゲットの破壊個数の期待値は最大いくらになるか.

□解法
まず,tiでソートします.ターゲットiを破壊し最適な行動をとった時の最大期待値Eiは,
Ei=pi+MAXj(tj-ti≧|cj-ci|)Ej
となります.
ですので,tiが大きいものからEiを求めていき,全て求め終わった後,最も大きいEiが答えとなります.

□コード
import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;

public class C{
Scanner sc=new Scanner(System.in);

int n;
R[] rs;

double EPS=1e-6;

void run(){
n=sc.nextInt();
rs=new R[n];
for(int i=0; i<n; i++){
R r=new R();
r.x=sc.nextInt();
r.y=sc.nextInt();
r.t=sc.nextInt();
r.p=sc.nextDouble();
rs[i]=r;
}
Arrays.sort(rs, new Comparator<R>(){
@Override
public int compare(R r1, R r2){
return r2.t-r1.t;
}
});
for(int j=0; j<n; j++){
R r=rs[j];
r.E+=r.p;
for(int i=j+1; i<n; i++){
R s=rs[i];
double d=Math.sqrt((r.x-s.x)*(r.x-s.x)+(r.y-s.y)*(r.y-s.y));
if(d<r.t-s.t+EPS){
s.E=Math.max(s.E, r.E);
}
}
}
double ans=0;
for(R r : rs){
ans=Math.max(ans, r.E);
}
println(""+ans);
}

class R{
int x, y, t;
double p;
double E;
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new C().run();
}
}


■Result
○×○××
1636p
151位

■Rating
1759 -> 1709

さらにRatingダウン.Bを落としたのが痛かった….

Codeforces Beta Round #28

Codeforces Beta Round #28 9/18(0:00~2:00)

久し振りのCodeforces.今回もCodeforces format.

■A. Bender Problem
□問題
複数の釘,長さが異なる複数の(金属)棒がある.釘を頂点,棒を辺として多角形を作れるかどうかを判定せよ.但し,個々の棒は任意の位置で1度折り曲げる必要がある.

□解法
例えば釘が4本,棒が2本とし,釘の座標をp1,p2,p3,p4とする.棒を折り曲げる座標は,p1,p3かp2,p4の2通りとなるため,それぞれが可能かを調べれば良い.

□コード
import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;

public class A{
Scanner sc=new Scanner(System.in);

int n, m;

int[] x, y;
int[] rod;

void run(){
n=sc.nextInt();
m=sc.nextInt();
x=new int[n];
y=new int[n];
rod=new int[m];
for(int i=0; i<n; i++){
x[i]=sc.nextInt();
y[i]=sc.nextInt();
}
for(int i=0; i<m; i++)
rod[i]=sc.nextInt();

boolean f1=true;
boolean f2=true;

int[] ans1=new int[n];
boolean[] selected=new boolean[m];

Arrays.fill(ans1, -1);
Arrays.fill(selected, false);
for(int k=0; k<n; k+=2){
// k-1,k,k+1
int x1=x[(k-1+n)%n];
int y1=y[(k-1+n)%n];
int x2=x[k];
int y2=y[k];
int x3=x[k+1];
int y3=y[k+1];
int len1=(int)Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
int len2=(int)Math.sqrt((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2));
boolean f=false;
for(int i=0; i<m; i++){
if(!selected[i]&&len1+len2==rod[i]){
selected[i]=true;
ans1[k]=i+1;
f=true;
break;
}
}
if(!f){
f1=false;
break;
}
}

int[] ans2=new int[n];
Arrays.fill(ans2, -1);
Arrays.fill(selected, false);
for(int k=1; k<n; k+=2){
// k-1,k,k+1
int x1=x[k-1];
int y1=y[k-1];
int x2=x[k];
int y2=y[k];
int x3=x[(k+1)%n];
int y3=y[(k+1)%n];
int len1=(int)Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
int len2=(int)Math.sqrt((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2));
boolean f=false;
for(int i=0; i<m; i++){
if(!selected[i]&&len1+len2==rod[i]){
selected[i]=true;
ans2[k]=i+1;
f=true;
break;
}
}
if(!f){
f2=false;
break;
}
}

if(f1||f2){
println("YES");
if(f1){
for(int i=0; i<n; i++)
print(ans1[i]+" ");
println("");
}
else if(f2){
for(int i=0; i<n; i++)
print(ans2[i]+" ");
println("");
}
}else{
println("NO");
}

}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new A().run();
}
}


■B. pSort
□問題
n個のセルがある.セルiとセルjはある条件にて各々が持つ値を交換する事が出来る.
初期状態では,n個のセルは,それぞれ1,2,…,n-1,nという値を持っている.
n個のセルの最終状態とどのセル同士が値を交換できるかの情報が与えられた時,初期状態から最終状態への遷移が可能かどうかを判定せよ.

□解法
交換できるセルは互いに素な集合.
例えば,0,…,7まであるとして,
集合1 : 0,3,5,6
集合2 : 1,2,4
集合3 : 7
がそれぞれ互いの値を交換出来る等.
だから,どのセルとどのセルが交換できるかを無向グラフで表現し,強連結成分分解した後,union-find木を作り,最終状態と比較すれば良い(と思う).最終状態は,順番はともかく集合としては,初期状態と同一のもので無ければならない.

□コード
import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;

public class B{
Scanner sc=new Scanner(System.in);

int n;
int[] a;
int[] fav;

void run(){
n=sc.nextInt();
a=new int[n];
fav=new int[n];
for(int i=0; i<n; i++)
a[i]=sc.nextInt()-1;
for(int i=0; i<n; i++)
fav[i]=sc.nextInt();

V[] vs=new V[n];
for(int i=0; i<n; i++)
vs[i]=new V(i);
boolean[][] added=new boolean[n][n];
for(int j=0; j<n; j++){
for(int i=0; i<n; i++){
if((Math.abs(j-i)==fav[i]||Math.abs(j-i)==fav[j])&&!added[j][i]){
added[j][i]=true;
vs[i].add(vs[j]);
}
}
}
scc(vs);

parent=new int[n];
rank=new int[n];

for(int i=0; i<n; i++)
makeSet(i);

for(int j=0; j<n; j++)
for(int i=0; i<n; i++)
if(vs[i].comp==vs[j].comp)
union(i, j);

for(int i=0; i<n; i++){
if(!sameComponents(i, a[i])){
println("NO");
return;
}
}
println("YES");
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new B().run();
}

// Union-Find

int[] parent;
int[] rank;

void makeSet(int x){
parent[x]=x;
rank[x]=0;
}

void union(int x, int y){
link(findSet(x), findSet(y));
}

boolean sameComponents(int x, int y){
return findSet(x)==findSet(y);
}

void link(int x, int y){
if(rank[x]>rank[y]){
parent[y]=x;
}else{
parent[x]=y;
if(rank[x]==rank[y])
rank[y]++;
}
}

int findSet(int x){
if(parent[x]!=x)
parent[x]=findSet(parent[x]);
return parent[x];
}

// Strongly Connected Components

int m;
V[] us;

int scc(V[] vs){
m=vs.length;
us=new V[m];
for(V v : vs)
if(!v.visit)
dfs(v);
for(V v : vs)
v.visit=false;
for(V u : us)
if(!u.visit)
dfsrev(u, m++);
return m;
}

void dfs(V v){
v.visit=true;
for(V u : v.fs)
if(!u.visit)
dfs(u);
us[--m]=v;
}

void dfsrev(V v, int k){
v.visit=true;
for(V u : v.rs)
if(!u.visit)
dfsrev(u, k);
v.comp=k;
}

// 頂点
static class V{
// 接続している頂点
LinkedList<V> fs=new LinkedList<V>();
// 接続されている頂点
LinkedList<V> rs=new LinkedList<V>();
boolean visit;
int comp;

int id;
V(int id){
this.id=id;
}

void add(V to){
fs.add(to);
to.rs.add(this);
}
}
}


C以降はどうにも解けませんでした.

■Result
○○×××
998p
158位

■Rating
1851 -> 1759

不覚にもRatingダウン.3問以上解かないとRating上昇は見込めません.

2010年9月22日水曜日

M-Judge 10158 Dungeon Wall

ACM-ICPC JAG Summer Camp 2010, Day 4
Problem D: Dungeon Wall
より
import java.util.*;
import java.lang.*;
import java.math.*;

public class Main{

Scanner sc=new Scanner(System.in);

int INF=1>>28;

int w, h, n;
int ix, iy, ox, oy;

boolean[][][] can;
int[] dx={0, 1, 0, -1};
int[] dy={-1, 0, 1, 0};

boolean[][] visited;
int[][] dist;
P[][] ps;

void run(){
w=sc.nextInt();
h=sc.nextInt();
n=sc.nextInt();
can=new boolean[h][w][4];
for(int j=0; j<h; j++)
for(int i=0; i<w; i++)
for(int k=0; k<4; k++)
can[j][i][k]=true;

for(int j=0; j<h; j++){
can[j][0][3]=false;
can[j][w-1][1]=false;
}
for(int i=0; i<w; i++){
can[0][i][0]=false;
can[h-1][i][2]=false;
}

for(int i=0; i<n; i++){
int sx=sc.nextInt();
int sy=sc.nextInt();
int tx=sc.nextInt();
int ty=sc.nextInt();
int x1=Math.min(sx, tx);
int x2=Math.max(sx, tx);
int y1=Math.min(sy, ty);
int y2=Math.max(sy, ty);

if(x1==x2){
for(int y=y1; y<y2; y++){
if(x1>0)
can[y][x1-1][1]=false;
if(x1<w)
can[y][x1][3]=false;
}
}else{
// y1==y2
for(int x=x1; x<x2; x++){
if(y1>0)
can[y1-1][x][2]=false;
if(y1<h)
can[y1][x][0]=false;
}
}
}

ix=sc.nextInt();
iy=sc.nextInt();
ox=sc.nextInt();
oy=sc.nextInt();

visited=new boolean[h][w];
dist=new int[h][w];
ps=new P[h][w];
for(int j=0; j<h; j++)
for(int i=0; i<w; i++)
ps[j][i]=new P(i, j);

int minDist=bfs();
int maxdist=minDist;
for(int j=0; j<h; j++){
for(int i=0; i<w; i++){
if(can[j][i][0]){
can[j][i][0]=false;
can[j-1][i][2]=false;
int d=bfs();
if(d!=INF)
maxdist=Math.max(maxdist, bfs());
can[j][i][0]=true;
can[j-1][i][2]=true;
}
if(can[j][i][1]){
can[j][i][1]=false;
can[j][i+1][3]=false;
int d=bfs();
if(d!=INF)
maxdist=Math.max(maxdist, bfs());
can[j][i][1]=true;
can[j][i+1][3]=true;
}
}
}
// println(minDist+"");
// println(maxdist+"");
println((maxdist-minDist)+"");
}

int bfs(){
for(int j=0; j<h; j++){
for(int i=0; i<w; i++){
visited[j][i]=false;
dist[j][i]=0;
}
}
LinkedList<P> q=new LinkedList<P>();
q.addLast(ps[iy][ix]);
visited[iy][ix]=true;
for(; !q.isEmpty();){
P p=q.removeFirst();
if(p.x==ox&&p.y==oy)
return dist[p.y][p.x];
for(int d=0; d<4; d++){
int x=p.x+dx[d];
int y=p.y+dy[d];
if(can[p.y][p.x][d]&&!visited[y][x]){
q.addLast(ps[y][x]);
visited[y][x]=true;
dist[y][x]=dist[p.y][p.x]+1;
}
}
}
return INF;
}

class P{
int x, y;

P(int x, int y){
this.x=x;
this.y=y;
}
}

public static void main(String[] args){
new Main().run();
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}
}

M-Judge 10157 Save your cats

ACM-ICPC JAG Summer Camp 2010, Day 4
Problem C: Save your cats
より
import java.util.*;
import java.lang.*;
import java.math.*;

public class Main{

Scanner sc=new Scanner(System.in);

int n, m;
int[] x, y;

int INF=1>>28;

int[] p;
int[] rank;

void run(){
n=sc.nextInt();
m=sc.nextInt();
x=new int[n];
y=new int[n];

for(int i=0; i<n; i++){
x[i]=sc.nextInt();
y[i]=sc.nextInt();
}

double sumW=0.0;
E[] es=new E[m];
for(int i=0; i<m; i++){
int p=sc.nextInt()-1;
int q=sc.nextInt()-1;
double w=Math.sqrt((x[q]-x[p])*(x[q]-x[p])+(y[q]-y[p])*(y[q]-y[p]));
sumW+=w;
es[i]=new E(p, q, w);
}

Arrays.sort(es, new Comparator<E>(){
public int compare(E e1, E e2){
return e1.w<e2.w?1:-1;
}
});

p=new int[n];
rank=new int[n];
for(int i=0; i<n; i++)
p[i]=i;

double extW=0.0;
for(E e : es){
if(findSet(e.v)!=findSet(e.u)){
extW+=e.w;
union(e.v, e.u);
}
}
println((sumW-extW)+"");
}

void union(int x, int y){
x=findSet(x);
y=findSet(y);
if(rank[x]>rank[y]){
p[y]=x;
}else{
p[x]=y;
if(rank[x]==rank[y]){
rank[y]++;
}
}
}

int findSet(int x){
if(p[x]!=x)
p[x]=findSet(p[x]);
return p[x];
}

public static void main(String[] args){
new Main().run();
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

class E{
int v, u;
double w;

E(int v, int u, double w){
this.v=v;
this.u=u;
this.w=w;
}
}
}

ただし,実行時間3:00[s]超.

M-Judge 10156 Kaeru Jump

ACM-ICPC JAG Summer Camp 2010, Day 4
Problem B: Kaeru Jump
より
import java.util.*;
import java.lang.*;
import java.math.*;

public class Main{

Scanner sc=new Scanner(System.in);

int h, w;
int[][] a;
int x0, y0;
int dir;

int[] dx={0, 1, 0, -1};
int[] dy={-1, 0, 1, 0};
char[] dc={'U', 'R', 'D', 'L'};

int nLeaf;

LinkedList<Character> solution;

void run(){
solution=new LinkedList<Character>();
h=sc.nextInt();
w=sc.nextInt();
a=new int[h][w];

for(int j=0; j<h; j++){
String s=sc.next();
for(int i=0; i<w; i++){
char c=s.charAt(i);
if(c=='.'){
a[j][i]=-1;
}else if(c=='o'){
a[j][i]=nLeaf++;
}else{
a[j][i]=nLeaf++;
x0=i;
y0=j;
switch(c){
case 'U':
dir=0;
break;
case 'R':
dir=1;
break;
case 'D':
dir=2;
break;
case 'L':
dir=3;
break;
}
}
}
}
sol();
}

void sol(){
// show();
rec(x0, y0, dir, nLeaf);
for(char c : solution)
print(c+"");
println("");
}

boolean solved=false;

void show(){
for(int j=0; j<h; j++){
for(int i=0; i<w; i++){
print(a[j][i]+", ");
}
println("");
}
println("");
}

void rec(int x, int y, int dir0, int leaf){
if(leaf==1){
// println(Arrays.toString(solution.toArray()));
solved=true;
return;
}
// show();
int l=a[y][x];
a[y][x]=-1;
for(int d=-1; d<=1; d++){
int dir=(dir0+d+4)%4;
int i=x;
int j=y;
for(; i>=0&&i<w&&j>=0&&j<h; i+=dx[dir], j+=dy[dir]){
if(a[j][i]>=0){
solution.addLast(dc[dir]);
rec(i, j, dir, leaf-1);
if(solved)
return;
solution.removeLast();
break;
}
}
}
a[y][x]=l;
}

public static void main(String[] args){
new Main().run();
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}
}

M-Judge 10146 Carrot Tour

ACM-ICPC JAG Summer Camp 2010, Day 3
Problem B: Carrot Tour
より
import java.util.*;
import java.lang.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main{
Scanner sc=new Scanner(System.in);

final int INF=1>>28;
final double EPS=1e-9;

int n;
double r;
double theta;
int[] xs, ys;
double[][] cost;
boolean[][][] can;

void run(){
n=sc.nextInt();
r=sc.nextDouble();
theta=sc.nextDouble();
xs=new int[n];
ys=new int[n];
cost=new double[n][n];
can=new boolean[n][n][n];
for(int i=0; i<n; i++){
xs[i]=sc.nextInt();
ys[i]=sc.nextInt();
}

for(int j=0; j<n; j++){
for(int i=0; i<n; i++){
double dx=xs[j]-xs[i];
double dy=ys[j]-ys[i];
if(i==j)
cost[j][i]=INF;
else
cost[j][i]=Math.sqrt(dx*dx+dy*dy);
}
}

// i->j->k
for(int k=0; k<n; k++){
for(int j=0; j<n; j++){
if(j==k)
continue;
for(int i=0; i<n; i++){
if(i==k||i==j)
continue;
double x1=xs[j]-xs[i];
double y1=ys[j]-ys[i];
double x2=xs[k]-xs[j];
double y2=ys[k]-ys[j];
double cost=(x1*x2+y1*y2)
/Math.sqrt((x1*x1+y1*y1)*(x2*x2+y2*y2));
if(Math.cos(Math.toRadians(theta))<cost+EPS)
can[i][j][k]=true;
}
}
}

double dp[][]=new double[n][n];
double t[][]=new double[n][n];

for(int j=0; j<n; j++)
for(int i=0; i<n; i++)
t[i][j]=INF;
for(int j=0; j<n; j++)
t[0][j]=cost[0][j];

for(int c=0;; c++){
boolean f=false;
for(int j=0; j<n; j++)
for(int i=0; i<n; i++)
if(t[j][i]<r+EPS)
f=true;
if(!f){
println(c+"");
return;
}

for(int k=0; k<n; k++){
for(int j=0; j<n; j++){
dp[j][k]=INF;
for(int i=0; i<n; i++){
if(can[i][j][k]){
dp[j][k]=Math.min(dp[j][k], t[i][j]+cost[j][k]);
}
}
}
}
for(int j=0; j<n; j++)
for(int i=0; i<n; i++)
t[j][i]=dp[j][i];
}
}

public static void main(String[] args){
new Main().run();
}

void print(String s){
System.out.print(s);
}

void println(String s){
System.out.println(s);
}

void println(){
System.out.println();
}

}

M-Judge 10145 Ennichi

ACM-ICPC JAG Summer Camp 2010, Day 3
Problem A: Ennichi
より
import java.util.*;
import java.lang.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main{
Scanner sc=new Scanner(System.in);

final int INF=1>>30;
final double EPS=1e-9;

int h, w, n;
char[][] a;

void run(){
h=sc.nextInt();
w=sc.nextInt();
n=sc.nextInt();
a=new char[h][w];
for(int j=0; j<h; j++){
String s=sc.next();
for(int i=0; i<w; i++){
a[j][i]=s.charAt(i);
}
}

for(int j=0; j<h; j++){
for(int i=0; i<w-1; i++){
if(a[j][i]==a[j][i+1])
continue;

// swap(i,j)<->(i+1,j)
char c=a[j][i];
a[j][i]=a[j][i+1];
a[j][i+1]=c;

if(check()){
println("YES");
return;
}

c=a[j][i];
a[j][i]=a[j][i+1];
a[j][i+1]=c;
}
}
println("NO");
}

void show(char[][] a){
for(int j=0; j<h; j++){
for(int i=0; i<w; i++){
print(a[j][i]+"");
}
println("");
}
}

boolean check(){
boolean[][] clear;
char[][] a=new char[h][w];
for(int j=0; j<h; j++)
for(int i=0; i<w; i++)
a[j][i]=this.a[j][i];

for(;;){
// 落下
for(int i=0; i<w; i++){
for(int j=1; j<h; j++){
if(a[j][i]!='.')
continue;
for(int k=j; k>0; k--)
a[k][i]=a[k-1][i];
a[0][i]='.';
}
}

boolean cl=false;
clear=new boolean[h][w];

for(int y=0; y<h; y++){
for(int x=0; x<w; x++){
// (x, y)から縦/横を調べる
if(a[y][x]=='.')
continue;

boolean f=true;
for(int y2=y; y2<y+n; y2++){
if(y2>=h||a[y2][x]!=a[y][x]){
f=false;
break;
}
}
if(f){
for(int y2=y; y2<h&&a[y2][x]==a[y][x]; y2++)
clear[y2][x]=true;
cl=true;
}

f=true;
for(int x2=x; x2<x+n; x2++){
if(x2>=w||a[y][x2]!=a[y][x]){
f=false;
break;
}
}
if(f){
for(int x2=x; x2<w&&a[y][x2]==a[y][x]; x2++)
clear[y][x2]=true;
cl=true;
}
}
}

for(int j=0; j<h; j++)
for(int i=0; i<w; i++)
if(clear[j][i])
a[j][i]='.';

if(!cl)
break;
}
for(int j=0; j<h; j++)
for(int i=0; i<w; i++)
if(a[j][i]!='.')
return false;
return true;
}

public static void main(String[] args){
new Main().run();
}

void print(String s){
System.out.print(s);
}

void println(String s){
System.out.println(s);
}

void println(){
System.out.println();
}
}

M-Judge 10136 友だちの誘い方

ACM-ICPC JAG Summer Camp 2010, Day 2
Problem B: 友だちの誘い方
より
import java.util.*;
import java.lang.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main{
Scanner sc=new Scanner(System.in);

final int INF=1>>30;
final double EPS=1e-9;

int n;
int[] a, b, c;

int max=131072;
int[] tree;

void run(){
tree=new int[max*2-1];
n=sc.nextInt();
a=new int[n];
b=new int[n];
int r=0;
for(int i=0; i<n; i++){
a[i]=sc.nextInt();
b[i]=sc.nextInt();
update(a[i], b[i]+1, 0, 0, max);
r=Math.max(r, b[i]);
}

for(int i=r; i>=2; i--){
int c=query(i);
if(i<=c+1){
println((i-1)+"");
return;
}
}
println("0");
}

void update(int a, int b, int k, int left, int right){
// println(""+a+","+b+","+k+","+left+","+right);
if(right<=a||b<=left)
return;
if(a<=left&&right<=b){
tree[k]++;
return;
}
update(a, b, k*2+1, left, (left+right)/2);
update(a, b, k*2+2, (left+right)/2, right);
}

int query(int k){
int ret=0;
for(int i=k+max-1;;){
ret+=tree[i];
if(i==0)
break;
i=(i-1)/2;
}
return ret;
}

public static void main(String[] args){
new Main().run();
}

void print(String s){
System.out.print(s);
}

void println(String s){
System.out.println(s);
}

void println(){
System.out.println();
}
}

ただし,実行時間3:00[s]超.

M-Judge 10135 雅先生の地球侵略日誌

ACM-ICPC JAG Summer Camp 2010, Day 2
Problem A: 雅先生の地球侵略日誌
より
import java.util.*;
import java.lang.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main{
Scanner sc=new Scanner(System.in);

final int INF=1>>30;
final double EPS=1e-9;

void run(){
long n=sc.nextLong()-1;
long r=1;
int ans=0;
for(; n/r!=0; r*=3, ans++);
println(""+ans);
}

public static void main(String[] args){
new Main().run();
}

void print(String s){
System.out.print(s);
}

void println(String s){
System.out.println(s);
}

void println(){
System.out.println();
}
}

ACM-ICPC JAG Summer Camp 2010

国内予選から早2ヶ月半.
この時期は毎年,OB/OG の会による夏合宿が開かれるようです.
チームnyamaは14位だった為参加できませんでした(10位以内でないとダメ)が,合宿中のコンテストには参加出来るようなので参加してきました.

問題はhttp://m-judge.maximum.vc/より閲覧出来ます.

■Day2
寝坊.13:00頃から参戦しました.

A 雅先生の地球侵略日誌
適当に小さい値で試してみると,log3Nみたいな感じ.ちゃっちゃと書いて提出.

B 友だちの誘い方
どうやって解くんだろう
->[i人なら問題無い人]の人数ciを数える
->ci+1<=iなら,ci人誘える
->これを全てのiに対してループしてmaxを取れば…
->提出
->TLE
->O(n2)で,n<=105だからTLEになるのは当たり前じゃないか
->Segment Tree使えばいいんじゃね?
->初めてのSegment Tree
->何か速くなった
->提出
->通ったー…?
->制限時間03:00[s],実行時間04:37[s]
->ACはしたけど,Standsには影響しませんでした…

正式にACしたのは1問だけという残念振り.

■Day3
11:00項からの参戦.

A Ennichi
落ちゲーのシミュレーションすればいいのかな
->提出
->WA
->あれ…
その後,ACしたのは随分後になってからでした.まさか落下処理を間違えていたとは….

B Carrot Tour
グラフ問題
->とりあえず,(i,j)間コストと,i->jと来た後kに進めるかを求めよう
->とりあえず,DFS
->とりあえず,サンプル合う
->とりあえず,提出
->とりあえず,TLE

全くやり方が思い浮かびませんでした.
終了後,red.cliff.jpの診断人さんのニコ生にて
[前のノード][今のノード][ニンジンの本数]=最短距離
のDPが出ていたので,サクサクッと組んだら,ACしました.

結局,この日も1問しか解けませんでした.

■Day4
ほぼ開始時刻直後から参戦.

A Alien's Counting
うーむ,とりあえずグラフにしてみよう
->連結でない所は,全く関わり合いがないので,強連結成分分解して,それぞれ求めて掛け合わせればいいのかな?(と意味不明な供述をしており)
->それぞれの値を求められない…

結局解けませんでした…

B Kaeru Jump
単純にDFSするだけでは?
->通った

D Dungeon Wall
壁が作れそうな所に作ってBFSするだけかな?
->TLE,BFS間違ってた
->修正,AC

H Ropeway
何か問題を読み間違えまくって,最終的には難しい問題だと分かりました…

この日は2問.もう一問位解きたいものです.

2010年9月18日土曜日

TopCoder 練習

HanoiGoodAndBad(Member SRM 482 Div1 Medium)

LayCurseさんのブログ
ゲームにっき(仮) | SRM482 DIV1 参加記録:
を参考に解く.

import java.util.*;
import java.lang.*;

public class HanoiGoodAndBad{
LinkedList<Integer> a,b,c;
int dave;
int step;

public int moves(int n, int dave){
this.dave=dave;
a=new LinkedList<Integer>();
b=new LinkedList<Integer>();
c=new LinkedList<Integer>();
for(int i=0;i<n;i++)
a.addLast(i);
step=0;
solve(a,b,c,n);

//System.out.println(Arrays.toString(a.toArray()));
//System.out.println(Arrays.toString(b.toArray()));
//System.out.println(Arrays.toString(c.toArray()));

return rec(a,b,c,n-1);
}

int rec(LinkedList<Integer> a,LinkedList<Integer> b, LinkedList<Integer> c,int k){
if(a.contains(k))
return rec(a,b,c,k-1);
else if(b.contains(k))
return (int)Math.pow(3,k)+rec(c,b,a,k-1);
else if(c.contains(k))
return 2*(int)Math.pow(3,k)+rec(a,b,c,k-1);
else
return 0;
}

void solve(LinkedList<Integer> a,LinkedList<Integer> b, LinkedList<Integer> c, int k){
if(k==0)
return;
solve(a,c,b,k-1);
if(step==dave) return;
c.addFirst(a.removeFirst());
step++;
if(step==dave) return;
solve(b,a,c,k-1);
}
}

TopCoder 練習

LockersDivOne(Member SRM 482 Div1 Easy)

愚直なシミュレーションでも動くことを確認.

public class LockersDivOne{
public int lastOpened(int n){
int[] a=new int[n];
int[] b=new int[n];
int last=n;
for(int i=0;i<n;i++)
a[i]=i;
for(int s=2;;s++){
int k=0;
for(int i=0;i<last;i++){
if(i%s!=0)
b[k++]=a[i];
}
last=k;
if(last<=1)
return b[0]+1;
for(int i=0;i<last;i++)
a[i]=b[i];
}
}
}

2010年9月16日木曜日

TopCoder Member SRM 482

Member SRM 482(9/16 0:00~2:00)

先週に引き続き.

■LockersDivOne(DIV1 Easy)

□Problem
1~N(1≦N≦2000000)まで番号付けされたロッカーがある.全てのロッカーは,閉じられている.
DaveとEarlは,番号の昇順にロッカーを見ていき,最初に見つけた閉じられているロッカーを開ける.その後,閉じられているロッカーを2個見つける度にそのロッカーを開けていく.番号Nまで戻ったら,はじめに戻り,2個飛ばしを3個飛ばしにし,同様のことをする.以降,4,5,6,…とロッカーを飛ばす個数を増やしていく.最後に残ったロッカーの番号は何か.

最初はLinkedListで実装しましたが,最大ケースを試したところ,メモリが足りないと言われかなり焦りました.しょうが無いので配列による実装に落ち着きましたが,最初から配列による実装にしていれば,もっと早く提出出来たと思います.ただ,今回は,Resubmitを一度もしないで済んだので,104.04pでした.

□Code
import java.util.*;
import java.lang.*;
import java.math.*;

public class LockersDivOne{
public int lastOpened(int N){
int[] a=new int[10000];
int[] b=new int[N];
for(int i=0;i<N;i++){
for(int k=2;k<a.length;k++){
if(a[k]==0){
a[k]++;
b[i]=k;
// System.out.println("i="+i+", k="+k);
break;
}else{
a[k]++;
}
if(a[k]==k)
a[k]=0;
}
}
int ret=0;
for(int i=0;i<N;i++){
if(b[i]>b[ret])
ret=i;
//if(b[i]<2)
// System.out.println("Error!");
}
//System.out.println(Arrays.toString(b));
//System.out.println(Arrays.toString(a));
return ret+1;
}
}


■Challenge
は,今回やりませんでした.

■Result
○×× 0 -0
104.04p

■Rating
1339 -> 1372
やっとhighestを更新しました.今年中には1500まで上げたいと思います.

2010年9月13日月曜日

PKU Judge Online 1664 放苹果

■1664 放苹果

□Problem
m個のリンゴをn皿に分配する.分配の仕方は何通りあるかを求めよ.
m=7,n=3の時は,
7 0 0
6 1 0
5 2 0
5 1 1
4 3 0
4 2 1
3 3 1
3 2 2
の8種類.

□Solution
f(m,n,e)
m個のリンゴをn皿に分配する組.ただしそれぞれの皿のリンゴはe個以下とする.
f(0,0,e)=1
…0個のリンゴを0皿に分配する方法は1通り
f(m,0,e)=0 (m>0)
…1個以上のリンゴを0皿には分配できない
f(m,n,e)=Σi=[i,min(m,e)]f(m-i,n-1,min(i,e))
…まず1つの皿にリンゴを置く,その際,置けるリンゴの個数iは,[1,min(m,e)]まで.
そしてリンゴをi個置いたら,残りn-1皿にはm-i個のリンゴを置くことになるが,それぞれの皿のリンゴの個数の上限は,min(i,e)となる.
上の式より,再帰的に求める(mとnが与えられたらf(m,n,m)を呼び出せばよい).

□Code
package p1664;

import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;

import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main{

Scanner sc=new Scanner(System.in);

final int INF=Integer.MAX_VALUE;
final double EPS=1e-9;

void run(){
for(int t=sc.nextInt(); t>0; t--){
int m=sc.nextInt();
int n=sc.nextInt();
println(""+f(m, n, m));
}
}

// m個のリンゴをn皿に分配する
// ただしそれぞれの皿のリンゴはe個以下
int f(int m, int n, int e){
if(n==0)
return m==0?1:0;
int ret=0;
// ある皿に置けるリンゴの個数iは,0<=1<=min(m(上限), e(制約))
// ある皿にリンゴをi個置くと,m-i個のリンゴを残りn-1皿に分配することになる
// ただしそれぞれの皿のリンゴはmin(i(上限), e(制約))個以下
for(int i=0; i<=Math.min(m, e); i++)
ret+=f(m-i, n-1, Math.min(i, e));
return ret;
}

void print(String s){
System.out.print(s);
}

void println(String s){
System.out.println(s);
}

public static void main(String[] args){
// System.setOut(new PrintStream(new BufferedOutputStream(System.out)));
new Main().run();
}
}

PKU Judge Online 1455 Crazy tea party

■1455 Crazy tea party

□Problem
n人のcrazy tea party参加者が円テーブルに座っている.各ステップで,1組の隣り合う2人が位置を交代することが出来る.n人の位置を逆順にするための最小ステップ数を求めよ.

□Solution
f(n)=最小ステップ数
g(n)=n人が一直線上に座っているとした時の反転にかかる最小ステップ数とする.

g(n)を求める.
n=5の時,
12345

23451
ここまでで,n-1ステップかかる.
残り2345を反転させるためにはg(4)ステップかかる.
よって,
g(n)=g(n-1)+n-1
g(1)=1
となるため,
g(n)=n(n-1)/2

f(n)を求める.
n人を2分割してそれぞれを反転させる(3分割してそれぞれを反転させても逆順にはならないので意味が無い).
123|456

321|654
n=2mの時は,
g(n)+g(n)<g(n-k)+g(n+k) (k>0)
より,丁度真ん中で分割した時が最小ステップとなる.
f(n)=g(m)+g(m)
n=2m+1の時も,(多分)同様にして示せるため
f(n)=g(m)+g(m+1)

□Code
package p1455;

import java.util.*;
import java.lang.*;
import java.math.*;

public class Main{
Scanner sc=new Scanner(System.in);

void run(){
for(int t=sc.nextInt(); t>0; t--){
int n=sc.nextInt();
int r=n/2;
int s=n-r;
int ans=r*(r-1)/2+s*(s-1)/2;
println(""+ans);
}
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new Main().run();
}
}

PKU Judge Online 1517 u Calculate e

■1517 u Calculate e

□Problem
マクローリン展開によるeの計算過程を表示せよ.

□Solution
やっつけ.BigDecimalで求めた結果をベタ貼りです.

□Code
package p1517;

import java.util.*;
import java.lang.*;
import java.math.*;

public class Main{
Scanner sc=new Scanner(System.in);

void run(){
println("n e");
println("- -----------");
println("0 1");
println("1 2");
println("2 2.5");
println("3 2.666666667");
println("4 2.708333333");
println("5 2.716666667");
println("6 2.718055556");
println("7 2.718253968");
println("8 2.718278770");
println("9 2.718281526");
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new Main().run();
}
}

PKU Judge Online 1565 Skew Binary

■1565 Skew Binary

□Problem
10120(skew)=1*(25-1)+0*(24-1)+1*(23-1)+2*(22-1)+0*(21-1)
という方法で値を計算せよ.

□Solution
やるだけ.

□Code
package p1565;

import java.util.*;
import java.lang.*;
import java.math.*;

public class Main{
Scanner sc=new Scanner(System.in);

void run(){
for(;;){
String s=sc.next();
if(s.equals("0"))
break;
long ans=0;
long sum=0;
for(char c : s.toCharArray()){
int d=c-'0';
ans=ans*2+d;
sum+=d;
}
ans*=2;
ans-=sum;
println(""+ans);
}
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new Main().run();
}
}

PKU Judge Online 1477 Box of Bricks

■1477 Box of Bricks

□Problem
いくつかのブロックを縦に並べた列がいくつかある.全ての列の高さを平坦化するのに必要なブロックの移動回数の最小値を求めよ.
(便宜上90°回転してます)
■■■■■
■■
■■■■

■■■■■■■
■■■■■

■■■■
■■■■
■■■■
■■■■
■■■■
■■■■

□Solution
やるだけ.

□Code
package p1477;

import java.util.*;
import java.lang.*;
import java.math.*;

public class Main{
Scanner sc=new Scanner(System.in);

void run(){
for(int s=1;; s++){
int n=sc.nextInt();
if(n==0)
break;
int[] a=new int[n];
int ave=0;
for(int i=0; i<n; i++)
ave+=a[i]=sc.nextInt();
ave/=n;
int ans=0;
for(int i=0; i<n; i++)
if(a[i]>ave)
ans+=a[i]-ave;
println("Set #"+s);
println("The minimum number of moves is "+ans+".");
println("");
}
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new Main().run();
}
}

PKU Judge Online 1458 Common Subsequence

■1458 Common Subsequence

□Problem
文字列sとtのLCS(Longest Common Subsequence:最長共通部分文字列)を求めよ.

□Solution
lcs(i,j)をsのi文字目までの部分文字列とtのj文字目までの部分文字列のLCSとすると,
lcs(i,0)=0
lcs(0,j)=0
lcs(i,j)=lcs(i-1,j-1)+1 (sのi文字目とtのj文字目が等しい場合)
lcs(i,j)=max(lcs(i,j-1),lcs(i-1,j)) (sのi文字目とtのj文字目が等しくない場合)
これらを使ってDP.

□Code
package p1458;

import java.util.*;
import java.lang.*;
import java.math.*;

public class Main{
Scanner sc=new Scanner(System.in);

void run(){
for(; sc.hasNext();){
String s=sc.next();
String t=sc.next();
int m=s.length();
int n=t.length();
int[][] dp=new int[n+1][m+1];
for(int j=1; j<=n; j++){
for(int i=1; i<=m; i++){
if(s.charAt(i-1)==t.charAt(j-1))
dp[j][i]=dp[j-1][i-1]+1;
else
dp[j][i]=Math.max(dp[j-1][i], dp[j][i-1]);
}
}
println(""+dp[n][m]);
}
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new Main().run();
}
}

PKU Judge Online 1423 Big Number

■1423 Big Number

□Problem
n!は10進数表記で何桁になるか求めよ.

□Solution
ある自然数mが10進数表記でd(m)桁になるとき,
d(m)=[log10(m)]+1
が成り立つ.
よって,
d(n!)
=[log10(n!)]+1
=[Σk=[1,n]log10(k)]+1

d(n!)を1≦n≦107について予め求めておく.

□Code
package p1423;

import java.util.*;
import java.lang.*;
import java.math.*;

public class Main{
Scanner sc=new Scanner(System.in);

void run(){
int n=(int)1e7;
int[] d=new int[n+1];
double a=0.0;
for(int i=1; i<=n; i++){
a+=Math.log10(i);
d[i]=(int)a+1;
}
for(int t=sc.nextInt(); t>0; t--){
int k=sc.nextInt();
println(d[k]+"");
}
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new Main().run();
}
}

PKU Judge Online 1401 Factorial

■1401 Factorial

□Problem
n!を10進数で表した時,最下桁から続く0の個数を求めよ.

□Solution
やるだけ.

□Code
package p1401;

import java.util.*;
import java.lang.*;
import java.math.*;

public class Main{
Scanner sc=new Scanner(System.in);

void run(){
for(int t=sc.nextInt(); t>0; t--){
long n=sc.nextLong();
long ans=0;
for(long r=5; r<=n; r*=5)
ans+=n/r;
println(ans+"");
}
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new Main().run();
}
}

PKU Judge Online 1218 THE DRUNK JAILER

■1218 THE DRUNK JAILER

□Problem
ある刑務所には部屋がn個(1,2,3,…,n)ある.
ある夜,退屈していた看守は,ゲームを始めた.
1.各部屋(1,2,3,…)の鍵を開けていく.
2.1つ飛ばしに各部屋(2,4,6,…)の鍵を閉めていく.
3.2つ飛ばしに各部屋(3,6,9,…)の鍵を開けていく.

n.n-1つ飛ばしに各部屋(nのみ)の鍵を開けていく.
最終的に,鍵が空いている部屋はいくつあるか.

□Solution
やるだけ.

□Code

package p1218;

import java.util.*;
import java.lang.*;
import java.math.*;

public class Main{
Scanner sc=new Scanner(System.in);

void run(){
for(int t=sc.nextInt();t>0;t--){
int n=sc.nextInt();
int[] a=new int[n];
// 0-lock
// 1-unlock
for(int k=1;k<=n;k++)
for(int i=k-1;i<n;i+=k)
a[i]=1-a[i];
int ans=0;
for(int e:a)
ans+=e;
println(""+ans);
}
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new Main().run();
}
}

2010年9月12日日曜日

PKU Judge Online 1012 Joseph

■1012 Joseph

□Problem
Josephの問題がある.これは,1~nまで数字付けされたn人が円状に並び,1の人からm人毎に省いていき,最後に残った人が生き残る,というものである.今回は,0<k<14となるkが与えられ,2k人が並ぶ.前半k人よりも先に後半k人が先に省かれるような最小のmを求めよ.

□Solution
kの範囲が狭いので,先に答えを求めておく.mの計算方法はコードのm(int k)を見て下さい.

□Code
package p1012;

import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;

import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main{

Scanner sc;

final int INF=Integer.MAX_VALUE;
final double EPS=1e-9;

void run(){
sc=new Scanner(System.in);
int[] ans={0, 2, 7, 5, 30, 169, 441, 1872, 7632, 1740, 93313, 459901,
1358657, 2504881};
for(;;){
int k=sc.nextInt();
if(k==0)
break;
println(""+ans[k]);
}
}

void debug(){
for(int k=1; k<14; k++)
println("k="+k+", m="+m(k));
}

int m(int k){
int n=k*2;
LinkedList<Integer> a=new LinkedList<Integer>();
for(int m=1;; m++){
a.clear();
for(int i=0; i<n; i++)
a.add(i);
int p=0;
boolean f=true;
for(int j=0; j<k; j++){
p=(p-1+m)%a.size();
if(a.remove(p)<k){
f=false;
break;
}
}
if(f)
return m;
}
}

void print(String s){
System.out.print(s);
}

void println(String s){
System.out.println(s);
}

public static void main(String[] args){
// System.setOut(new PrintStream(new BufferedOutputStream(System.out)));
new Main().run();
}
}

PKU Judge Online 1338 Ugly Numbers

■1338 Ugly Numbers

□Problem
素因数が2,3,5のみである自然数をugly numberと呼ぶ.n個目のugly numberを表示せよ.

□Solution
n≦1500であるので,先に生成しておけばよい.

□Code(かなり適当です)
package p1338;

import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;

import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main{

Scanner sc=new Scanner(System.in);

final int INF=Integer.MAX_VALUE;
final double EPS=1e-9;

void run(){
LinkedList<Long> list=new LinkedList<Long>();
long r5=1;
for(int k=0; k<14; k++){
if(r5>1000000000)
break;
long r3=1;
for(int j=0; j<19+1; j++){
if(r5*r3>1000000000)
break;
long r2=1;
for(int i=0; i<31; i++){
if(r2*r3*r5>1000000000)
break;
list.add(r2*r3*r5);
r2*=2;
}
r3*=3;
}
r5*=5;
}
Long[] a=list.toArray(new Long[0]);
sort(a);
for(;;){
int m=sc.nextInt();
if(m==0)
break;
println(a[m-1]+"");
}
}

boolean ugly(int n){
while(n%2==0)
n/=2;
while(n%3==0)
n/=3;
while(n%5==0)
n/=5;
return n==1;
}

void print(String s){
System.out.print(s);
}

void println(String s){
System.out.println(s);
}

public static void main(String[] args){
// System.setOut(new PrintStream(new BufferedOutputStream(System.out)));
new Main().run();
}
}

PKU Judge Online 1316 Self Numbers

■1316 Self Numbers

□Problem
自然数nに対し,d(n)をn+(各桁の総和)と定義する.例えば,d(75)=75+7+5=87.n=d(m)となるmが存在しないnをself-numberと呼ぶ.10000以下のself-numberを全て表示せよ.

□Solution
やるだけ.

□Code
package p1316;

import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;

import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main{

Scanner sc=new Scanner(System.in);

final int INF=Integer.MAX_VALUE;
final double EPS=1e-9;

void run(){
int n=10000;
int[] a=new int[n];
for(int i=1; i<n; i++){
int m=i;
int s=i;
while(m!=0){
s+=m%10;
m/=10;
}
if(s<n)
a[s]=1;
}
for(int i=1; i<n; i++)
if(a[i]==0)
println(i+"");
}

void print(String s){
System.out.print(s);
}

void println(String s){
System.out.println(s);
}

public static void main(String[] args){
// System.setOut(new PrintStream(new BufferedOutputStream(System.out)));
new Main().run();
}
}

PKU Judge Online 1163 The Triangle

■1163 The Triangle

□Problem
ピラミッド状になっている数字がある.
    7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
このピラミッドを一番上(ここでは7)から左下/右下へたどって行き,総和を取る.この総和の最大値を出力せよ.この例では,30(7->3->8->7->5)が最大値.

□Solution
下からDPしていくだけ.

□Code
package p1163;

import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;

import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main{

Scanner sc=new Scanner(System.in);

final int INF=Integer.MAX_VALUE;
final double EPS=1e-9;

void run(){
int n=sc.nextInt();
int[][] a=new int[n][n];
for(int j=0; j<n; j++)
for(int i=0; i<j+1; i++)
a[j][i]=sc.nextInt();

for(int j=n-2; j>=0; j--)
for(int i=0; i<j+1; i++)
a[j][i]+=max(a[j+1][i], a[j+1][i+1]);
println(a[0][0]+"");
}

void print(String s){
System.out.print(s);
}

void println(String s){
System.out.println(s);
}

public static void main(String[] args){
// System.setOut(new PrintStream(new BufferedOutputStream(System.out)));
new Main().run();
}
}

2010年9月11日土曜日

PKU Judge Online 1013 Counterfeit Dollar

■1013 Counterfeit Dollar

□Problem
12枚の銀貨があり,その内の1つは偽物である.偽物と本物とは重さが違うが,軽いか重いかはわからない.あなたは,天秤を3回用いて幾つかの銀貨の重さを比較し,左の皿に乗せたn枚,右の皿に乗せたn枚,右の皿が上がるor下がるor変わらない,という情報を得た.これより,偽物の銀貨を探し出し,かつ,それが本物より軽いか重いかを判定せよ.

□Solution
解は1つのみある,という制約があるため,12枚の銀貨それぞれが軽いor重い偽物だと想定し,与えられた情報にマッチするか判定するだけ.

□Code
package p1013;

import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;

import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main{

Scanner sc;

final int INF=Integer.MAX_VALUE;
final double EPS=1e-9;

void run(){
sc=new Scanner(System.in);
int n=sc.nextInt();
int[] a=new int[12];
for(int t=0; t<n; t++){
Case[] cases=new Case[3];
for(int j=0; j<3; j++){
cases[j]=new Case();
String s=sc.next();
for(char c : s.toCharArray())
cases[j].left.add(c-'A');
s=sc.next();
for(char c : s.toCharArray())
cases[j].right.add(c-'A');
s=sc.next();
if(s.equals("up"))
cases[j].res=-1;
else if(s.equals("down"))
cases[j].res=1;
else
cases[j].res=0;
}
fill(a, 2);
for(int j=0; j<24; j++){
int coin=j/2;
// heavy
if(j%2==0)
a[coin]=3;
// light
else
a[coin]=1;
boolean f=true;
for(Case c : cases){
int leftSum=0, rightSum=0;
for(int i : c.left)
leftSum+=a[i];
for(int i : c.right)
rightSum+=a[i];
if(leftSum>rightSum){
if(c.res!=-1){
f=false;
break;
}
}else if(leftSum<rightSum){
if(c.res!=1){
f=false;
break;
}
}else{
if(c.res!=0){
f=false;
break;
}
}
}
if(f){
println((char)(coin+'A')
+" is the counterfeit coin and it is "
+new String[]{"heavy", "light"}[j%2]+".");
break;
}
a[coin]=2;
}
}
}

class Case{
LinkedList<Integer> left=new LinkedList<Integer>();
LinkedList<Integer> right=new LinkedList<Integer>();
// right
// up=-1, down=1, even=0
int res;
}

void print(String s){
System.out.print(s);
}

void println(String s){
System.out.println(s);
}

public static void main(String[] args){
// System.setOut(new PrintStream(new BufferedOutputStream(System.out)));
new Main().run();
}
}

PKU Judge Online 1001 Exponentiation

■1001 Exponentiation

□Problem
Rnを計算せよ.
0.0<R<99.999
0<n<=25

□Solution
BigDecimal無限精度モード+正規表現 -> ^q^

□Code
package p1001;

import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;

import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main{

Scanner sc;

static final int INF=Integer.MAX_VALUE;
static final double EPS=1e-9;

void run(){
sc=new Scanner(System.in);
for(; sc.hasNext();){
BigDecimal r=sc.nextBigDecimal();
int n=sc.nextInt();
String ans=r.pow(n, MathContext.UNLIMITED).toPlainString()
.replaceAll("^0*|[.]?0*$", "");
println(ans);
}
sc.close();
}

void print(String s){
System.out.print(s);
}

void println(String s){
System.out.println(s);
}

public static void main(String[] args){
new Main().run();
}
}

2010年9月10日金曜日

Project Euler

problem 107
最小全域木.終了.

problem 205
[1,4]の四面体サイコロ9つと,[1,6]の立方体サイコロ6つでゲームを行う.それぞれの合計値を比較し,大きい方が勝ちとする.前者が勝つ確率は幾らか.
それぞれについて,0~36がそれぞれ何回出現するか数えて比較するだけ.

100問解いたので,やっとこさLevel 3になりました.

TopCoder Member SRM 481

SRM 481(9/9 20:00~22:00)

久しぶりのSRM.今回は,とりあえずEasy正答を目標に.

■ChickenOracle(Div1 Easy)

□Problem
あなたは,"卵が先か鶏が先か"問題の答えを知りたい.そんな時oracleは現れた.
しかし,あなたがどんなに尋ねても,oracleは答えを教えてくれない.その代わり,n人には既に答えを教えた"という.そこであなたは,そのn人に答えを尋ねてみたところ,eggCount人は"卵が先だ"と言い,残りのn-eggCount人は"鶏が先だ"と言う.困ったあなたはもう一度oracleに尋ねたところ,"lieCount人には嘘の答えを教えた.更にliarCount人は,あなたに(oracleが教えた)答えと反対の答えを言った"とのこと.これらの情報から,oracleの本当の答えを推測せよ.
返り値
"卵が先" -> "The egg"
"鶏が先" -> "The chicken"
どちらもあり得る -> "Ambiguous"
どちらもありえない -> "The oracle is a lie"

場合分けを沢山すれば解けるとは思うのですが,難しかったので,愚直にループを回しました.しかし,↓の回答に辿りつくまでに2回もResubmitしてしまった為,Scoreが75.0pになってしまいました.

□Code
import java.util.*;
import java.math.*;
import java.lang.*;

public class ChickenOracle{
public String theTruth(int n, int eggCount, int lie, int liar){
int e=eggCount;
int c=n-eggCount;

boolean ef=false;
boolean cf=false;

for(int i=0;i<=lie;i++){
int l1=i;
int l2=lie-l1;
int e1=e-l1;
int c1=c-l2;
if(e1<0||c1<0)
continue;
e1+=l2;
c1+=l1;
if(e1==liar) cf=true;
if(c1==liar) ef=true;
}

if(cf&&ef) return "Ambiguous";
else if(cf)return "The chicken";
else if(ef)return "The egg";
else return "The oracle is a lie";
}
}


■Challenge
一人,自分が陥っていたミスと同様のことをしていた人がいたので撃墜(+50).
もう一人,間違ってそうだからとチャレンジしたが撃墜失敗(-25).

■Result
○×× 50 -25
100.0p

■Rating
1282 -> 1339

とりあえず1300まで上昇.どうにか次回もRatingを上げたいものです.

2010年9月9日木曜日

Project Euler

problem 59
XORにより暗号化された文から平文を推測する問題.かなり適当に解いた.

problem 89
与えられたローマ数字を最小文字数で表す問題.文字の先読みをして適当に解く.

2010年9月8日水曜日

専門書を買う

Prologへの入門(PrologとAI)
プログラミングコンテストチャレンジブック

2010年9月7日火曜日

Prologの技芸 4.2節の練習問題

(1)
挿入ソート
sort([3,1,2],Ys)
sort([1,2],Zs1)
sort([2],Zs2)
sort([],Zs3) {Zs3=[]}
true
insert(2,[],Zs2) {Zs2=[2]}
true
insert(1,[2],Zs1) {Zs1=[2|Zs4]}
1>2
fail
insert(1,[2],Zs1) {Zs1=[1,2|[]]}
1=<2
true
insert(3,[1,2],Ys) {Ys=[1|Ys1]}
3>1
true
insert(3,[2],Ys1) {Ys1=[2|Ys2]}
3>2
true
insert(3,[],Ys2) {Ys2=[3]}
true


クイックソート
sort([3,1,2],Ys)
partition([1,2],3,Ls,Bs) {Ls=[1|Ls1]}
1 =< 3
true
partition([2],3,Ls1,Bs) {Ls1=[2|Ls2]}
2 =< 3
true
partition([],3,Ls2,Bs) {Ls2=[], Bs=[]}
true
sort([1,2],Ls3)
partition([2],1,Ls4,Bs1) {Ls4=[2|Ls5]}
2 =< 1
fail
partition([2],1,Ls4,Bs1) {Bs1=[2|Bs2]}
2 > 1
true
partition([],1,Ls4,Bs2) {Ls4=[], Bs2=[]}
true
sort([],Ls5) {Ls5=[]}
true
sort([2],Bs3)
partition([],2,Ls6,Bs4) {Ls6=[], Bs4=[]}
true
sort([],Ls7) {Ls7=[]}
true
sort([],Bs5) {Bs5=[]}
true
append([],[2],Bs3) {Bs3=[2]}
true
append([],[1,2],Ls3) {Ls3=[1,2]}
true
sort([],Bs6) {Bs6=[]}
true
append([1,2],[3],Ys) {Ys=[1,2,3]}
true


(2)
derivative(3*sin(x)-4*cos(x),x,D) {D=0}
constant(3*sin(x)-4*cos(x))
integer(3*sin(x)-4*cos(x))
fail
derivative(3*sin(x)-4*cos(x),x,D) {D=DF-DG}
derivative(3*sin(x),x,DF) {DF=0}
constant(3*sin(x))
integer(3*sin(x))
fail
derivative(3*sin(x),x,DF) {DF=3*DG1+DF1*sin(x)}
derivative(3,x,DF1) {DF1=0}
constant(3)
integer(3)
true
derivative(sin(x),x,DG1) {DG1=0}
constant(sin(x))
integer(sin(x))
fail
derivative(sin(x),x,DG1) {DG1=cos(x)}
true
derivative(4*cos(x),x,DG) {DG=0}
constant(4*cos(x))
integer(4*cos(x))
fail
derivative(4*cos(x),x,DG) {DG=4*DG1+DF1*cos(x)}
derivative(4,x,DF1) {DF1=0}
constant(4)
integer(4)
true
derivative(cos(x),x,DG1) {DG1=0}
constant(cos(x))
integer(cos(x))
fail
derivative(cos(x),x,DG1) {DG1=-sin(x)}
true

Prologの技芸 4.1節の練習問題

(1)
X=b
Xs=[]
Ys=[c,d]
L=[b|Zs]

(2)
N=s(0)
A=a
B=b
C=c
Ms=Xs

Prologの技芸 3.5節の練習問題

(1)
% arithmetic_sum(A + B) :-
% 算術和A+Bは,正規化されている.すなわちAが定数で,
% Bが算術和の正規表現となっている形式A+B.
:- op(600, xfy, +).
arithmetic_sum(A + B) :- atomic(A), arithmetic_sum(B).
arithmetic_sum(A) :- atomic(A).

演算子定義
:- op(500, fy,~).
:- op(550,xfy,&).
:- op(600,xfy,'|').

(2)
bool(true).
bool(false).
bool(X & Y) :- bool(X), bool(Y).
bool(X | Y) :- bool(X), bool(Y).
bool(~X) :- bool(X).

(3)
% 和積標準形(選言の連言)
cnf(F1 & F2) :- disjunctive(F1), cnf(F2).
cnf(F) :- disjunctive(F).
% 選言
disjunctive(F1 | F2) :- atomic_formula(F1), disjunctive(F2).
disjunctive(F) :- atomic_formula(F).
% 連言
conjunctive(F1 & F2) :- atomic_formula(F1), conjunctive(F2).
conjunctive(F) :- atomic_formula(F).
% リテラル
atomic_formula(X) :- atomic(X).
atomic_formula(~X) :- atomic(X).

(4)
% negation_inwards(F1,F2) :-
% F2は,論理式F1に現れる否定を
% 全て連言や選言の内側に移し変えて得られる論理式である.
negation_inwards(F1 & F2,G1 & G2) :-
negation_inwards(F1,G1), negation_inwards(F2,G2).
negation_inwards(F1 | F2,G1 | G2) :-
negation_inwards(F1,G1), negation_inwards(F2,G2).
negation_inwards(~(F1 & F2),G1 | G2) :-
negation_inwards(~F1,G1), negation_inwards(~F2,G2).
negation_inwards(~(F1 | F2),G1 & G2) :-
negation_inwards(~F1,G1), negation_inwards(~F2,G2).
negation_inwards(~ ~F,G) :- negation_inwards(F,G).
negation_inwards(F,F) :- atomic_formula(F).

2010年9月5日日曜日

Project Euler

problem 70
1<n<10において,10進数で表したφ(n)がnの並び替えになっているものの内,n/φ(n)が最大となるnを求めよ,という問題.
φ(n)の計算が予想以上に遅く,苦戦.最後はマシンパワーに頼った.

problem 80
1≦n≦100において,√n(ただし√nは無理数)の上位100桁をそれぞれ足しあわせた合計を求めよ,という問題.
BigDecimalの精度をMathContext.UNLIMITED(無制限)に設定し,愚直なループで√nを求めた.

2010年9月3日金曜日

Prologの技芸 3.4節の練習問題

(1)
% subtree(S,T) :-
% SはTの部分木である.
subtree(tree(X,L,R),tree(_,Left,_)) :-
subtree(tree(X,L,R),Left).
subtree(tree(X,L,R),tree(_,_,Right)) :-
subtree(tree(X,L,R),Right).
subtree(tree(X,Left,Right),tree(X,Left,Right)).

(2)
% sum_tree(TreeOfIntegers,Sum) :-
% Sumは整数の木TreeOfIntegersの整数要素の和である.
sum_tree(tree(X,Left,Right),Sum) :-
sum_tree(Left,SumLeft),
sum_tree(Right,SumRight),
Sum is SumLeft+SumRight+X.
sum_tree(void,0).

(3)
% ordered(TreeOfIntegers) :-
% TreeOfIntegersは整数の順序木である.
% ordered_left(X,Tree) :-
% XがTreeの根節点よりも小さく,かつTreeが順序木.
% ordered_right(X,Tree) :-
% XがTreeの根節点よりも小さく,かつTreeが順序木.
ordered(tree(X,Left,Right)) :-
ordered_left(X,Left),
ordered(Left),
ordered_right(X,Right),
ordered(Right).
ordered(void).
ordered_left(X,tree(Y,Left,Right)) :-
X > Y, ordered_left(Y,Left), ordered_right(Y,Right).
ordered_right(X,tree(Y,Left,Right)) :-
X < Y, ordered_left(Y,Left), ordered_right(Y,Right).
ordered_left(_,void).
ordered_right(_,void).

(4)
% tree_insert(X,Tree,Tree1) :-
% Tree1は順序木Tree中にXを挿入してできる順序木である.
tree_insert(X,tree(X,Left,Right),tree(X,Left,Right)).
tree_insert(X,tree(Y,Left,Right),tree(Y,Left1,Right)) :-
X < Y, tree_insert(X,Left,Left1).
tree_insert(X,tree(Y,Left,Right),tree(Y,Left,Right1)) :-
X > Y, tree_insert(X,Right,Right1).
tree_insert(X,void,tree(X,void,void)).

Project Euler

problem 72
problem 73

2010年9月2日木曜日

Prologの技芸 3.3節の練習問題

(1)
% substitute(X,Y,L1,L2) :-
% L2はL1中に現れるすべてのXをYで置き換えた結果である.
substitute(X,Y,[],[]).
substitute(X,Y,[X|Xs],[Y|Ys]) :- substitute(X,Y,Xs,Ys).
substitute(X,Y,[Z|Xs],[Z|Ys]) :- X \= Z, substitute(X,Y,Xs,Ys).

(2)
% select(X,Xs,Ys) :-
% Ysは,Xsの最先頭にあるXをXsから削除したリストである.
select(X,[X|Xs],Xs).
select(X,[Y|Ys],[Y|Zs]) :- X \= Y, select(X,Ys,Zs).

(3)
% no_doubles(L1,L2) :-
% L2はL1から重複する要素をすべて取り除いた結果である.
no_doubles([],[]).
no_doubles([X|Xs],Ys) :- member(X,Xs), !, no_doubles(Xs,Ys).
no_doubles([X|Xs],[X|Ys]) :- no_doubles(Xs,Ys).

(4)
% even_permutation(Xs,Ys) :-
% YsはリストXsの偶数順列である.
% odd_permutation(Xs,Ys) :-
% YsはリストXsの奇数順列である.
even_permutation([],[]).
odd_permutation([],[]).
even_permutation([X|Xs],Ys) :- odd_permutation(Xs,Ys).
odd_permutation([X|Xs],[X|Ys]) :- even_permutation(Xs,Ys).

(5)
% margesort(Xs,Ys) :-
% リストYsはリストXsの順序付けられた順列である.
margesort([],[]).
margesort([X],[X]).
margesort([X1,X2|Xs],Ys) :-
partition([X1,X2|Xs],Lefts,Rights),
margesort(Lefts,Ls),
margesort(Rights,Rs),
marge(Ls,Rs,Ys).

% partition(Xs,Lefts,Rights) :-
% LeftsとRightsはXsを大体半分ずつに分けたものである.
partition(Xs,Lefts,Rights) :-
length(Xs,Length),
half(Length,L,R),
prefix(Lefts,Xs),
length(Lefts,L),
append(Lefts,Rights,Xs),
length(Rights,R).

half(X,L,R) :-
X1 is X/2,
integer(X1),
L = X1,
R = X1.
half(X,L,R) :-
X1 is (X-1)/2,
integer(X1),
L = X1,
R is X-X1.

% marge(Xs,Ys,Zs) :-
% ZsはXsとYsを併合したものである.
marge([],Xs,Xs).
marge(Xs,[],Xs).
marge([X|Xs],[Y|Ys],[X|Zs]) :- X < Y, marge(Xs,[Y|Ys],Zs).
marge([X|Xs],[Y|Ys],[Y|Zs]) :- X >= Y, marge([X|Xs],Ys,Zs).

2010年9月1日水曜日

Prologの技芸 3.2節の練習問題

(2)
adjacent(X,Y,[X,Y|_]).
adjacent(X,Y,[_|Zs]) :- adjacent(X,Y,Zs).
last(X,[X]).
last(X,[_|Ys]) :- last(X,Ys).

(5)
% sum(Sum,ListOfIntegers) :-
% Sumは整数のリストListOfIntegersの要素の和である.

(a) plus/3を使った定義
natural_number(0).
natural_number(s(X)) :- natural_number(X).
plus(0,X,X) :- natural_number(X).
plus(s(X),Y,s(Z)) :- plus(X,Y,Z).
sum_a(0,[]).
sum_a(X,[Y|Ys]) :- sum_a(Z,Ys), plus(Y,Z,X).

(b) 補助述語を使わない定義
sum_b(0,[]).
sum_b(s(X),[s(Y)|Ys]) :- sum_b(X,[Y|Ys]).
sum_b(X,[0|Ys]) :- sum_b(X,Ys).