ラベル Google Code Jam の投稿を表示しています。 すべての投稿を表示
ラベル Google Code Jam の投稿を表示しています。 すべての投稿を表示

2011年6月6日月曜日

Google Code Jam 2011 Round2

GCJ2011 Round2(6/4 23:00~01:30)

Round2に進めただけでも,進歩を感じましたが,欲を出して,Tシャツを狙いに行きました.

■A. Airport Walkways

K[m]の道がある.あなたは,普段は速度S[m/s]で歩くが,(トータルで)t[s]だけ速度R[m/s]で走ることが出来る.
さらに道のいくつかの部分には,動く歩道が設置されており,その速度があなたの歩くor走る速度に上乗せされる.
最短何秒でK[m]移動することが出来るか.

どこ走るかがポイント.答えは,動く歩道の速度+歩く速度が小さいところをより優先する.
あとは,走った時間が正確にt[s]になるように気をつける.
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 INF=1<<28;
 double EPS=1e-9;

 int caze;
 int TT;
 int x, s, r, t, n;
 int[] b, e, w;

 void run(){
  TT=sc.nextInt();
  for(caze=1; caze<=TT; caze++){
   x=sc.nextInt();
   s=sc.nextInt();
   r=sc.nextInt();
   t=sc.nextInt();
   n=sc.nextInt();
   b=new int[n];
   e=new int[n];
   w=new int[n];
   for(int i=0; i<n; i++){
    b[i]=sc.nextInt();
    e[i]=sc.nextInt();
    w[i]=sc.nextInt();
   }
   solve();
  }
 }

 void solve(){
  int[] v=new int[x];
  fill(v, s);
  for(int j=0; j<n; j++){
   for(int i=b[j]; i<e[j]; i++){
    v[i]+=w[j];
   }
  }
  PriorityQueue<Integer> que=new PriorityQueue<Integer>();
  for(int i=0; i<x; i++){
   que.offer(v[i]);
  }
  double d=r-s;
  double remain=t;
  double ans=0;
  for(int i=0; i<x; i++){
   int u=que.poll();
   if(1.0/(u+d)>remain+EPS){
    double p=remain*(u+d);
    ans+=remain+(1.0-p)/u;
    remain=0;
   }else{
    remain-=1.0/(u+d);
    ans+=1.0/(u+d);
   }
  }
  answer(ans+"");
 }

 void answer(String s){
  println("Case #"+caze+": "+s);
 }

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

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

 void debug(Object... os){
  System.err.println(Arrays.deepToString(os));
 }

 public static void main(String[] args){
  try{
   System.setIn(new FileInputStream(
     "D:/contest_workspace/gcj_2011_round2/dat/A-large.in"));
   System.setOut(new PrintStream(new FileOutputStream(
     "D:/contest_workspace/gcj_2011_round2/dat/A-large.out")));
  }catch(Exception e){}

  new A().run();
  System.out.flush();
  System.out.close();
 }
}

■B. Spinning Blade

全探索で解ける.
愚直に実装すると,(x1, y1)-(x1, y1) からなる長方形の重心を求めるための計算量は, O(n5)となり(8分間では)絶対に間に合わない.
そこで,部分和を使う.
MX1(i, j)=Σ0≦k≦ia(k, j)k
MY1(i, j)=Σ0≦k≦ja(i, k)k
とする.
これで,ある行 or 列に対するある範囲の質量×位置の総和がO(1)で求まるため, 総計算量は、O(n4)になる.しかし,n=500なので,これでも厳しい.
最終的に,
MX2(i, j)=Σ0≦k≦iMX1(i, k)
MY2(i, j)=Σ0≦k≦jMY1(k, j)
とすると,
MX1(i, j) or MY1(i, j)は(1, 1)-(i, j)からなる長方形のxおよびy座標に関する質量×位置の総和になる.(1, 1)-(i, j)の長方形の総質量も同様にして求められるようにすれば,1クエリをO(1)で求めることが出来るため結局,総計算量がO(n3)になり間に合う.
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 INF=1<<28;
 double EPS=1e-9;

 int caze;
 int t;
 int m, n, d;
 long[][] a;

 void run(){
  t=sc.nextInt();
  for(caze=1; caze<=t; caze++){
   n=sc.nextInt();
   m=sc.nextInt();
   d=sc.nextInt();
   a=new long[n][m];
   for(int j=0; j<n; j++){
    String s=sc.next();
    for(int i=0; i<m; i++){
     a[j][i]=s.charAt(i)-'0'+d;
    }
   }
   solve();
  }
 }

 long[][] mx1, mx2, my1, my2, m1, m2;
 double gx, gy, g;

 void solve(){
  mx1=new long[n][m];
  mx2=new long[n][m];
  my1=new long[n][m];
  my2=new long[n][m];
  m1=new long[n][m];
  m2=new long[n][m];

  for(int j=0; j<n; j++){
   mx1[j][0]=a[j][0]*0;
   m1[j][0]=a[j][0];
   for(int i=1; i<m; i++){
    mx1[j][i]=mx1[j][i-1]+a[j][i]*i;
    m1[j][i]=m1[j][i-1]+a[j][i];
   }
  }

  for(int i=0; i<m; i++){
   mx2[0][i]=mx1[0][i];
   m2[0][i]=m1[0][i];
   for(int j=1; j<n; j++){
    mx2[j][i]=mx2[j-1][i]+mx1[j][i];
    m2[j][i]=m2[j-1][i]+m1[j][i];
   }
  }

  for(int i=0; i<m; i++){
   my1[0][i]=a[0][i]*0;
   for(int j=1; j<n; j++){
    my1[j][i]=my1[j-1][i]+a[j][i]*j;
   }
  }

  for(int j=0; j<n; j++){
   my2[j][0]=my1[j][0];
   for(int i=1; i<m; i++){
    my2[j][i]=my2[j][i-1]+my1[j][i];
   }
  }

  // 1クエリO(1)
  int ans=0;
  for(int y=0; y<n; y++){
   for(int x=0; x<m; x++){
    for(int w=3; x+w<=m&&y+w<=n; w++){
     calc(x, y, w);
     double mx=x+(w-1)/2.;
     double my=y+(w-1)/2.;
     if(abs(mx-gx)<EPS&&abs(my-gy)<EPS){
      ans=max(ans, w);
     }
    }
   }
  }
  answer(ans>0?(ans+""):"IMPOSSIBLE");
  debug(ans);
 }

 void calc(int x, int y, int w){
  gx=mx2[y+w-1][x+w-1];
  gy=my2[y+w-1][x+w-1];
  g=m2[y+w-1][x+w-1];
  if(x>0){
   gx-=mx2[y+w-1][x-1];
   gy-=my2[y+w-1][x-1];
   g-=m2[y+w-1][x-1];
  }
  if(y>0){
   gx-=mx2[y-1][x+w-1];
   gy-=my2[y-1][x+w-1];
   g-=m2[y-1][x+w-1];
  }
  if(x>0&&y>0){
   gx+=mx2[y-1][x-1];
   gy+=my2[y-1][x-1];
   g+=m2[y-1][x-1];
  }
  gx-=a[y][x]*x+a[y][x+w-1]*(x+w-1)+a[y+w-1][x]*x+a[y+w-1][x+w-1]*(x+w-1);
  gy-=a[y][x]*y+a[y][x+w-1]*y+a[y+w-1][x]*(y+w-1)+a[y+w-1][x+w-1]*(y+w-1);
  g-=a[y][x]+a[y][x+w-1]+a[y+w-1][x]+a[y+w-1][x+w-1];
  gx/=g;
  gy/=g;
 }

 void answer(String s){
  println("Case #"+caze+": "+s);
 }

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

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

 void debug(Object... os){
  System.err.println(Arrays.deepToString(os));
 }

 public static void main(String[] args){
  try{
   System.setIn(new FileInputStream(
     "D:/contest_workspace/gcj_2011_round2/dat/B-large.in"));
   System.setOut(new PrintStream(new FileOutputStream(
     "D:/contest_workspace/gcj_2011_round2/dat/B-large.out")));
  }catch(Exception e){}

  new B().run();
  System.out.flush();
  System.out.close();
 }
}
■Result 38pts. 756th 念願のTシャツゲットです.もう少し頑張れば,Round3に進めたかもしれないですが,ここ最近で最高レベルに集中出来たので良かったと思います.

2011年5月23日月曜日

Google Code Jam 2011 Round1B

せめて,Bは解いておこうかと.

■B. Revenge of the Hot Dogs

ご想像のとおり二分探索.
時間tに対して,各ホットドッグ屋がD離れることが出来るかを判定する必要がある.
これは,ホットドッグ屋を左から見ていき,可能な限り左に寄せていくことで判定できる.
二分探索の上限の見積もりが甘くLargeでWAってしまった….
import java.util.*;
import java.util.Map.Entry;
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);

 long INF=1L<<40;
 double EPS=1e-9;

 int caze;
 int n, d;
 R[] rs;

 void run(){
  int tt=sc.nextInt();
  for(caze=1; caze<=tt; caze++){
   n=sc.nextInt();
   d=sc.nextInt();
   rs=new R[n];
   for(int i=0; i<n; i++){
    int p=sc.nextInt();
    int m=sc.nextInt();
    rs[i]=new R(p, m);
   }
   solve();
  }
 }

 void solve(){
  long left=0, right=INF;
  for(int i=0; i<n; i++){
   rs[i].p*=2;
  }
  d*=2;

  sort(rs, new Comparator<R>(){
   @Override
   public int compare(R r1, R r2){
    return r1.p-r2.p;
   }
  });

  for(int i=0; i<1000; i++){
   long mid=(left+right)/2;
   if(check(mid)){
    right=mid;
   }else{
    left=mid;
   }
  }
  debug(right, right/2.0);
  answer(String.format("%.1f", right/2.0));
 }

 boolean check(long t){
  long left=-INF;
  for(int j=0; j<n; j++){
   for(int i=0; i<rs[j].m; i++){
    if(rs[j].p+t<left+d){
     return false;
    }
    left=max(left+d, rs[j].p-t);
    // [left+d, INF) and [p-t , p+t]
   }
  }
  return true;
 }

 class R{
  int p, m;
  R(int p, int m){
   this.p=p;
   this.m=m;
  }
 }

 void answer(String s){
  println("Case #"+caze+": "+s);
 }

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

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

 void debug(Object... os){
  System.err.println(Arrays.deepToString(os));
 }

 public static void main(String[] args){
  try{
   System.setIn(new FileInputStream(
     "D:/contest_workspace/gcj_2011_round1b/dat/B-large.in"));
   System.setOut(new PrintStream(new FileOutputStream(
     "D:/contest_workspace/gcj_2011_round1b/dat/B-large.out")));
  }catch(Exception e){}
  new B().run();
  System.out.flush();
  System.out.close();
 }
}

Google Code Jam 2011 Round1A

遅ればせながら,報告.

■A. FreeCell Statistics

まず,下記の2条件を満たすか調べる.
・PG=0の時は,PD=0でないといけない.
何故なら,PG=0ならば,全てのゲームで負けているから.
・PG=100の時は,PD=100でないといけない.
理由は上とほぼ同じ.

次に,勝率がPD[%]となる(今日の)最小のゲーム数を求める.
つまり,
PD/100*Dが整数となるような,最小のDを求める.
つまり,
D=100/gcd(PD,100)
である.
D≦Nならば,"Possible".
PGについては,試合の勝敗を調整すれば基本的に実現可能.
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 INF=1<<28;
 double EPS=1e-9;

 int caze;
 int t;
 long n, nd, ng;

 void run(){
  t=sc.nextInt();
  for(caze=1; caze<=t; caze++){
   n=sc.nextLong();
   nd=sc.nextLong();
   ng=sc.nextLong();
   solve();
  }
 }

 void solve(){
  long dd=100;
  long dg=100;
  if(ng==0&&nd>0){
   answer("Broken");
   return;
  }
  if(ng==100&&nd<100){
   answer("Broken");
   return;
  }
  long gcdD=gcd(nd, dd);
  long gcdG=gcd(ng, dg);
  debug(gcdD, gcdG);
  nd/=gcdD;
  dd/=gcdD;
  ng/=gcdG;
  dg/=gcdG;
  debug(nd, dd, ng, dg);
  long d=dd;
  if(d>n){
   answer("Broken");
   return;
  }
  answer("Possible");
 }

 void answer(String s){
  println("Case #"+caze+": "+s);
 }

 long gcd(long m, long n){
  for(; n!=0;){
   long t=m%n;
   m=n;
   n=t;
  }
  return m;
 }

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

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

 void debug(Object... os){
  System.err.println(Arrays.deepToString(os));
 }

 public static void main(String[] args){
  try{
   System.setIn(new FileInputStream(
     "D:/contest_workspace/gcj_2011_round1a/dat/A-large.in"));
   System.setOut(new PrintStream(new FileOutputStream(
     "D:/contest_workspace/gcj_2011_round1a/dat/A-large.out")));
  }catch(Exception e){}

  new A().run();
  System.out.flush();
  System.out.close();
 }
}

■B. The Killer Word

大雑把な方針は,DFSです.
まず,辞書単語を文字列の長さで分類します.
そして,リストの文字を順番に辞書全体に適用していきます.
その際,それぞれの辞書単語の開示状態は変わります.
この開示状態が等しいもので分類して,その集合で個々にDFSを行います.
集合の要素数が1になったら終わりです.
詳しい説明は,GCJ公式のContest Analysisを御覧下さい.
ちなみに,本番では解けませんでした.
import java.util.*;
import java.util.Map.Entry;
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 INF=1<<28;
 double EPS=1e-9;

 int caze;
 int m, n;
 String[] dic, lis;
 String l;

 int[] bit;
 int[] opend;
 int[][] open;
 int[] loses;

 void run(){
  int tt=sc.nextInt();
  for(caze=1; caze<=tt; caze++){
   m=sc.nextInt();
   n=sc.nextInt();
   dic=new String[m];
   lis=new String[n];
   for(int i=0; i<m; i++){
    dic[i]=sc.next();
   }
   for(int i=0; i<n; i++){
    lis[i]=sc.next();
   }
   solve();
  }
 }

 void dfs(TreeSet<Integer> set, int k, int exist){
  if(set.size()<=1||k>=26){
   return;
  }
  if(((exist>>(l.charAt(k)-'a'))&1)==0){
   dfs(set, k+1, exist);
   return;
  }
  HashMap<Integer, TreeSet<Integer>> map=new HashMap<Integer, TreeSet<Integer>>();
  HashMap<Integer, Integer> exists=new HashMap<Integer, Integer>();
  for(int i : set){
   opend[i]|=open[i][l.charAt(k)];
   if(open[i][l.charAt(k)]==0){
    loses[i]++;
   }
   if(!map.containsKey(opend[i])){
    map.put(opend[i], new TreeSet<Integer>());
    exists.put(opend[i], 0);
   }
   map.get(opend[i]).add(i);
   exists.put(opend[i], exists.get(opend[i])|bit[i]);
  }
  for(Entry<Integer, TreeSet<Integer>> entry : map.entrySet()){
   dfs(entry.getValue(), k+1, exists.get(entry.getKey()));
  }
 }

 void solve(){
  String ans="";
  for(int k=0; k<n; k++){
   TreeSet<Integer>[] sets=new TreeSet[10];
   for(int i=0; i<10; i++){
    sets[i]=new TreeSet<Integer>();
   }
   bit=new int[m];
   opend=new int[m];
   open=new int[m][256];
   loses=new int[m];
   int[] exists=new int[10];
   for(int j=0; j<m; j++){
    sets[dic[j].length()-1].add(j);
    for(int i=0; i<dic[j].length(); i++){
     bit[j]|=1<<(dic[j].charAt(i)-'a');
     open[j][dic[j].charAt(i)]|=1<<i;
     exists[dic[j].length()-1]|=1<<(dic[j].charAt(i)-'a');
    }
   }
   l=lis[k];
   for(int i=0; i<10; i++){
    dfs(sets[i], 0, exists[i]);
   }
   int max=-1;
   for(int i=0; i<m; i++){
    max=max(max, loses[i]);
   }
   for(int i=0; i<m; i++){
    if(loses[i]==max){
     ans+=dic[i]+(k==n-1?"":" ");
     break;
    }
   }
  }
  answer(ans);
  debug(ans);
 }

 void answer(String s){
  println("Case #"+caze+": "+s);
 }

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

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

 void debug(Object... os){
  System.err.println(Arrays.deepToString(os));
 }

 public static void main(String[] args){
  try{
   System.setIn(new FileInputStream(
     "D:/contest_workspace/gcj_2011_round1a/dat/B-large.in"));
   System.setOut(new PrintStream(new FileOutputStream(
     "D:/contest_workspace/gcj_2011_round1a/dat/B-large.out")));
  }catch(Exception e){}
  new B().run();
  System.out.flush();
  System.out.close();
 }
}

■Result

oo----
20pts. 870th
どうにかRound2へ進出出来ます.

2010年5月24日月曜日

Google Code Jam 2010 Round 1C

1Bで1000位以内に入れなかったので再び挑戦.

■問題A
ビルとビルの間に複数のロープを張っていく.双方のビルに張るロープの位置が与えられた時,何箇所が交差するか.

□解法A
これは見た瞬間解法が分かったので,small,large共に開始10分以内に提出できました.

import java.io.*;
import java.util.*;
public class A {
int cal(int n,int[] a,int[] b){
int res=0;
for(int j=0;j<n-1;j++)
for(int i=j+1;i<n;i++)
if((a[j]-a[i])*(b[j]-b[i])<0)
res++;
return res;
}
void a() throws Exception{
Scanner sc=new Scanner(new FileReader("D:\\google_code_jam\\gcj2010\\round1c\\a\\A-large.in"));
BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\google_code_jam\\gcj2010\\round1c\\a\\A-large.out"));
int T=sc.nextInt();
for(int k=0;k<T;k++){
int N=sc.nextInt();
int[] a=new int[N];
int[] b=new int[N];
for(int i=0;i<N;i++){
a[i]=sc.nextInt();
b[i]=sc.nextInt();
}
int ans=cal(N,a,b);
System.out.println("Case #"+(k+1)+": "+ans);
bw.write("Case #"+(k+1)+": "+ans);
bw.newLine();
}
bw.close();
}
}

■問題B
問題の内容がさっぱり分かりませんでした….

□解法B
省略.

■問題C
白と黒のタイルで構成されたボードからチェスボード(白と黒の市松模様)を切り出していく.出来るだけ大きいチェスボードから切り出していった時,どの大きさのものが幾つ出来るか.

□解法C
コードが物凄く汚い&smallしか解けないので省略.

■結果
ABC
small○(9)×(14)○(18)
large○(13)×(22)×(24)
point22018

40Point,1072位.

というわけで敗退.40Pointでも,早く解けた人はRound 2に進出出来たので,時間差といえば時間差です.が,もう少し,頭の切り替えが早ければ,1000以内に入れたかもしれません.

2010年5月23日日曜日

Google Code Jam 2010 Round 1B

■問題A
既に作られているディレクトリ構造と,これから作ろうとしているディレクトリ構造が与えられる.mkdirコマンドは何回実行する必要があるか.


□解法A
実装ゲー.ちまちましたミスでかなり手間取ってしまいました.

import java.io.*;
import java.util.*;

public class A {

class Node{
HashMap<String, Node> children=new HashMap<String, Node>();
}

long cal(int N, int M, String[] exist, String[] create){
Node root=new Node();

for(int i=0;i<N;i++){
String[] s=exist[i].split("/");
Node node=root;
for(int k=1;k<s.length;k++){
if(!node.children.containsKey(s[k]))
node.children.put(s[k], new Node());
node=node.children.get(s[k]);
}
}

long ret=0;
for(int i=0;i<M;i++){
String[] s=create[i].split("/");
Node node=root;
for(int k=1;k<s.length;k++){
if(!node.children.containsKey(s[k])){
ret++;
node.children.put(s[k], new Node());
}
node=node.children.get(s[k]);
}
}

return ret;
}

void a() throws Exception{
Scanner sc=new Scanner(new FileReader("D:\\google_code_jam\\gcj2010\\round1b\\a\\A-large.in"));
BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\google_code_jam\\gcj2010\\round1b\\a\\A-large.out"));

int T=sc.nextInt();
for(int k=0;k<T;k++){
int N=sc.nextInt();
int M=sc.nextInt();
sc.nextLine();

String[] exist=new String[N];
for(int i=0;i<N;i++)
exist[i]=sc.nextLine();

String[] create=new String[M];
for(int i=0;i<M;i++)
create[i]=sc.nextLine();

long ans=cal(N,M,exist,create);
System.out.println("Case #"+(k+1)+": "+ans);
bw.write("Case #"+(k+1)+": "+ans);
bw.newLine();
}
bw.close();
}
}


■問題B
沢山のヒヨコちゃんがレール上にいる.それぞれのヒヨコはある方向に走っており,後方のヒヨコちゃんは,前方のヒヨコちゃんに追いついてしまったら,前方のヒヨコちゃんと同じ速度に減速する.また,クレーンを使って隣り合う2匹のヒヨコちゃんを交換することが出来る.N匹のヒヨコに対し,初期位置xi[m]と速度vi[m/s]が与えられる.K(≦N)匹のヒヨコがT[s]以内でB[m]の地点に到達するように,クレーンでヒヨコを移動させた時,その最小回数はいくらか.


□解法B
ヒヨコ?クレーン?といった感じで,問題文を理解するのにかなりの時間が掛かってしまいました.分かった後はこれまた実装ゲー.

import java.io.*;
import java.util.*;

public class B {

String cal(int N,int K,long B,int T,int[] x,int[] v){
boolean[] barn=new boolean[N];
int nBarn=0;
for(int i=0;i<N;i++){
int p=x[i]+v[i]*T;
if(p>=B)
nBarn++;
barn[i]=p>=B;
}
if(nBarn<K)
return "IMPOSSIBLE";

int pick=0;
int j=N;
for(int k=0;k<K;k++){
while(!barn[--j]);
for(int i=j;i+1<N&&!barn[i+1];i++){
boolean f=barn[i];
barn[i]=barn[i+1];
barn[i+1]=f;
pick++;
}
}

return ""+pick;
}

void a() throws Exception{
Scanner sc=new Scanner(new FileReader("D:\\google_code_jam\\gcj2010\\round1b\\b\\B-large.in"));
BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\google_code_jam\\gcj2010\\round1b\\b\\B-large.out"));

int C=sc.nextInt();
for(int k=0;k<C;k++){
int N=sc.nextInt();
int K=sc.nextInt();
long B=sc.nextLong();
int T=sc.nextInt();
int[] x=new int[N];
int[] v=new int[N];

for(int i=0;i<N;i++)
x[i]=sc.nextInt();
for(int i=0;i<N;i++)
v[i]=sc.nextInt();

String ans=cal(N,K,B,T,x,v);
System.out.println("Case #"+(k+1)+": "+ans);
bw.write("Case #"+(k+1)+": "+ans);
bw.newLine();
}
bw.close();
}

}


■問題C
a1, …, ak=nという数列がある.nはk番目,kはi番目,iはj番目,…という操作の結果,最終的にa1は1番目,となるような数列はいくつあるか.与えられる数はnのみ.


□解法C
コーディングが間に合わず.

■結果
ABC
small○(12)○(13)×(14)
large○(14)○(17)×(30)
point26300

56Point,1257位.

1000位以内に入れなかったのでRound2に進めず….18:00からのRound1Cで1000位以内に入れなかったら敗退.

2010年5月9日日曜日

Google Code Jam 2010 Qualification Round (After)

■問題A
2進カウンタをK回進めたとき,下位Nビットが全て1なら"ON",そうでないなら"OFF"を出力せよ.

□解法B
ビット演算でクールにキメたかったのですが,あまり自信が無かったため,Kを2進文字列に直した後,下位Nビットが全て1であるか調べました.
import java.io.*;
public class A {
public void a() throws Exception{
BufferedReader br=new BufferedReader(new FileReader("C:\\A-large.in"));
BufferedWriter bw=new BufferedWriter(new FileWriter("C:\\A-large.out"));
int T=Integer.parseInt(br.readLine());
for(int i=0;i<T;i++){
String[] s=br.readLine().split(" ");
int N=Integer.parseInt(s[0]);
int K=Integer.parseInt(s[1]);
String t=toBS(K);
boolean f=true;
for(int j=t.length()-N;j<t.length();j++){
if(j<0||t.charAt(j)!='1'){
f=false;
break;
}
}
String ans="Case #"+(i+1)+": "+(f?"ON":"OFF");
bw.write(ans);
bw.newLine();
}
bw.close();
}
String toBS(int n){
if(n==0)
return "0";
String s="";
while(n!=0){
s=n%2+s;
n/=2;
}
return s;
}
}

■問題B
長い文章でしたが,問題自体は↓.
maxy gcd(t1+y, t2+y, …, tN+y)となる最小のyを求めよ.

□解法B
まず,gcd(t1+y, t2+y, …, tN+y)=mとします.
このとき,
m|ti+y (1≦i≦N)
であるため,
m|(ti+y)-(tj+y) (1≦i, j≦N)
よって,
m|ti-tj (1≦i, j≦N)
ここで,
gcd1≦i, j≦N(ti-tj)=n
とすれば,n=m(のはずです…).
あとは,m|t1+yとなるようにyを求めて((m-t1)%mを計算する)終わり.
import java.io.*;
import java.math.*;
import java.util.*;

public class B {
BigInteger calcY(int N,BigInteger[] t){
Arrays.sort(t);

LinkedList<BigInteger> list=new LinkedList<BigInteger>();
for(int j=0;j<N-1;j++)
for(int i=j+1;i<N;i++)
list.add(t[j].subtract(t[i]));
BigInteger gcd=list.get(0);
for(BigInteger bi:list)
gcd=bi.gcd(gcd);
return gcd.subtract(t[0]).mod(gcd);
}

public void b() throws Exception{
BufferedReader br=new BufferedReader(new FileReader("C:\\B-large.in"));
BufferedWriter bw=new BufferedWriter(new FileWriter("C:\\B-large.out"));
int C=Integer.parseInt(br.readLine());
for(int i=0;i<C;i++){
String[] s=br.readLine().split(" ");
int N=Integer.parseInt(s[0]);
BigInteger[] t=new BigInteger[N];
for(int j=0;j<N;j++)
t[j]=new BigInteger(s[j+1]);
BigInteger y=calcY(N,t);
String ans="Case #"+(i+1)+": "+y;
bw.write(ans);
bw.newLine();
}
bw.close();
}
}

■問題C
1人以上の客から構成されるグループがNグループある.1Euro/人とすると,k人乗りのローラーコースターをR回走らせた時,いくら稼げるか.

R=4,k=6,N=4として,グループ毎の人数を[1,4,2,1]と表すと,以下のようになります.

回数乗っているグループ待っているグループ儲け
1[1, 4][2, 1]5
2[2, 1, 1][4]4
3[4, 2][1, 1]6
4[1, 1 ,4][2]6

□解法C
R>Nであれば,必ず,以前走らせた時と同じパターンが出てくるので,それを記憶しておき…としたのですが,コーディングをミスした模様.largeでエラー連発でした.

■結果
ABC
small
large×
point333310

76Point,2318位.

とりあえずは予選通過,ということで.

Google Code Jam 2010 Qualification Round (Before)

ついにやってきました.Google Code Jam 2010.
Google Code Jam

Google Code Jamとは,Google主催のプログラミングコンテストで,2003年から年1回開催されます.
実は,前回も挑戦したのですが,全く歯が立ちませんでした.というわけで,今回は予選通過を目標にしました.

予選のQualification Roundは,日本時間で5/8AM8:00より24時間でしたので解いてきました.
とりあえず,A,Bに関してsmall,large共に提出できました(Cではlarge失敗).今回は,A,B,Cの内small,large共に正答しているものが一つでもあれば予選通過になります.

結果が出次第,詳細を追って報告します.