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

2011年9月18日日曜日

Codeforces Beta Round #87 Div. 1 Only

Codeforces Beta Round #86 Div. 1 Only (9/16 0:00~2:00)

■A. Party

解法

グラフに注目したとき下のような列があったとする.
A1->A2->…->AN
この列の中の任意の2ノードは, 同じグループに属することができないため, 最低でもNグループ必要だと分かる.
このようなNの中で最大のものNmaxを見つければ, 任意の列は,長さが高々Nmaxなので, Nmax個のグループに高々1人で振り分けることが出来る.
結局,Nmaxが答え.
#86 Div. 1 A. Party

■B. Lawnmower

解法

ジグザグに進んでいくため,貪欲に求めることが出来る.
#86 Div. 1 B. Lawnmower

■Result

oo--- 1146pts. 256th
1700→1717

2011年9月11日日曜日

Codeforces Beta Round #86 Div. 1 Only

Codeforces Beta Round #86 Div. 1 Only (9/9 0:00~2:00)

■A. A Grammar Lessons

問題

Petyaの作った言語は以下のBNFにより定義される.与えられた文字列がSentenceか判定せよ.

Sentence := Statement | AdjectiveM | AdjectiveF | NounM | NounF | VerbM | VerbF
Statement := (AdjectiveM* NounM VerbM*) | (AdjectiveF* NounF VerbF*)

AdjectiveM := "lios" | Alphabet AdjectiveM
AdjectiveF := "liala" | Alphabet AdjectiveF
NounM := "etr" | Alphabet NounM
NounF := "etra" | Alphabet NounF
VerbM := "initis" | Alphabet VerbM
VerbF := "inites" | Alphabet VerbF

Alphabet := "a"|"b"|"c"|…|"z"

解法

書くだけ.StatementのBNFをDFAにしてからコードにすると,機械的に解ける.
#86 Div. 1 A. A Grammar Lessons

■B. Petr#

問題

文字列s,sbegin,sendが与えられる.
以下を満たす文字列tの個数を求めよ.
  • tはsの部分文字列
  • sbeginはtのprefix
  • sendはtのsuffix

解法

sにおいて,sbeginおよびsendを検索して,インデックスの候補を列挙する.
sbegin,sendに関するインデックスks,keについて,
s[ks]からsbeginがあり,
s[ke]からsendがあり,
ks≦ke かつ ks+|sbegin|≦ke+|send|
ならば,
s[ks],…,s[ke],…,s[ke+|send|-1]
が条件を満たす文字列.
条件を満たす文字列を逐一生成すると,TLEするので,
ハッシュを計算し,重複要素を取り除くことで高速化.
#86 Div. 1 B. Petr#

■Result

o---- 254pts. 215th
1684->1700

2011年9月4日日曜日

Codeforces Beta Round #85 Div. 1 Only

Codeforces Beta Round #85 Div. 1 Only (9/4 21:00~23:00)

■A. Petya and Inequiations

問題

n,x,yが与えられる.
a12+a22+…+an2≥x
a1+a2+…+an≤y
を満たす正整数の列
a1,a2,…,an
を求めよ.なければ,-1を返せ.

解法

a1+a2+…+an
の最小値はn.次に,
a1+a2+…+an=y
としたとき,
a12+a22+…+an2
の最大値は,
ak=1 (1≤k≤n-1)
an=y-(n-1)
のとき,この値(=(n-1)+(y-(n-1))2)がx以上なら数列(ak)が答え.
#85 Div. 1 A. Petya and Inequiations

■B. Petya and Divisors

問題

2つの数列
x1,…,xn
y1,…,yn
が与えられる.
各(xi, yi)について,
xi mod k=0 かつ (∀j:i-yi≤j<i) xj mod k ≠ 0
なる正整数kの数を求めよ.

解法

xiの各約数di,kについて,
それがx1,…,xi-1の約数である最後のインデックスp[di,k]を記録しておく.
p[di,k]<i-yiなら条件を満たす.
その後,
p[di,k]=i
と更新.
#85 Div. 1 B. Petya and Divisors

■Result

o---- 484pts. 278th
1689 -> 1684

ドカーン.

2011年9月3日土曜日

Codeforces Beta Round #84 Div. 2 Only

Codeforces Beta Round #84 Div. 2 Only 8/30 1:00~3:00)

■A. Nearly Lucky Number

問題

Lucky Digitを,4または7として定義する.
Lucky Numberは,Lucky Digitのみで表現される(10進)数のことである.
Nearly Lucky Numberとは,ある数に含まれるLucky Digitの個数が,Lucky Numberである数のことである.
与えられた数が,Nearly Lucky Numberかどうかを判定せよ.

解法

やるだけ.
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;

	void run(){
		long n=sc.nextLong();
		int c=0;
		for(; n>0; n/=10){
			if(n%10==4||n%10==7){
				c++;
			}
		}
		boolean f=c>0;
		for(; c>0; c/=10){
			f&=c%10==4||c%10==7;
		}
		println(f?"YES":"NO");
	}

	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){
		new A().run();
	}
}

■B. Lucky String

問題

Lucky Stringとは, ある文字列において出現するアルファベットのインデックスをアルファベット毎に分類・ソートしたときに, 隣り合うインデックスの差がLucky Numberである文字列のことである.
長さnのLucky Stringの内,辞書式順で最も早いものを出力せよ.

解法

abcdabcd…
↑これをn文字出力するだけ.
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;

	void run(){
		int n=sc.nextInt();
		StringBuffer sb=new StringBuffer("");
		for(int i=0; i<n;){
			for(char c='a'; c<='d'&&i<n; c++, i++){
				sb.append(c);
			}
		}
		println(sb.toString());
	}

	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){
		new B().run();
	}
}

■C. Lucky Sum of Digits

問題

各桁の総和がnとなる最小のLucky Numberを求めよ.

解法

4の個数と,7の個数が固定ならば,
44…4477…77
という形のLucky Numberが最小であることは明らか.
次に,4の個数をa,7の個数をbとすると,
4a+7b=n
が成立する.
(例えば28で考えれば分かるが) 上の条件を満たす(a, b)の中で,bが最大ものが最小のLucky Numberとなることは明らか.
従って,aを0から逐次増やしていき, (n-4a) mod 7=0となればそこで計算を終了すればいい.
そのようなaが見つからずにループが終了したときは,条件を満たすLucky Numberは存在しない.
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 INF=1<<28;
	double EPS=1e-9;

	int n;

	void run(){
		n=sc.nextInt();
		for(int a=0; n-4*a>=0; a++){
			if((n-4*a)%7==0){
				int b=(n-4*a)/7;
				StringBuffer sb=new StringBuffer();
				for(int i=0; i<a; i++){
					sb.append('4');
				}
				for(int i=0; i<b; i++){
					sb.append('7');
				}
				println(sb.toString());
				return;
			}
		}
		println("-1");
	}

	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){
		new C().run();
	}
}

■E. Lucky Tree

問題

ノード数n,辺の数n-1の非循環無向グラフ(=全域木)が与えられる.
各辺には,重みがついている.
次の条件を満たす3つ組(i,j,k)の数を求めよ.
  • iからjの経路にはLucky Numberを重みとして持つ辺が少なくとも1つある.
  • iからkの経路にはLucky Numberを重みとして持つ辺が少なくとも1つある.

解法

例えば,グラフが以下のようなものだったとする.
ここで,点線になっている辺は,Lucky Numberの重みを持つ.
ポイントは,上の条件を満たさない3つ組みを求める方が簡単だということ.
例えば,グループ1に注目してみる.
グループ1から選んだ3ノードより構成される3つ組み (v1,v2,v3)は,決して上の条件を満たさない.
また,グループ1から2ノード(v1,v2とする)を選び, グループ1以外の任意の1ノード(uとする)を選んだとき,
(v1,v2,u),(v1,u,v2)
も上の条件を満たさない.
つまり,あるグループkがmノードから構成されているとすれば,
m(m-1)(m-2)+2m(m-1)(n-m)
が,グループkのノードを2つ以上含みかつ上の条件を満たさ「ない」3つ組みの総数となる.
全てのグループについて上式の和を計算したものをsumとする.
最後に,nノードから3つ選ぶ順列の総数はn(n-1)(n-2)であるから,
n(n-1)(n-2)-sumが答えとなる.
さて,どうやってグラフ構造をグループに分け,そのグループのノード数を計算するだが, これについては,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 E{
	Scanner sc=new Scanner(System.in);

	int INF=1<<28;
	double EPS=1e-9;

	int n;

	void run(){
		n=sc.nextInt();
		make(n);

		for(int i=0; i<n-1; i++){
			int u=sc.nextInt()-1;
			int v=sc.nextInt()-1;
			int w=sc.nextInt();
			if(!isLucky(w)){
				union(u, v);
			}
		}

		debug(p);

		long ans=0;
		for(int i=0; i<n; i++){
			long s=size(i);
			if(p[i]>=0){
				continue;
			}
			if(s>=3){
				ans+=s*(s-1)*(s-2);
			}
			if(s>=2){
				ans+=s*(s-1)*(n-s)*2;
			}
		}

		// debug(n*(n-1)*(n-2));
		// debug(ans);
		ans=(long)n*(n-1)*(n-2)-ans;
		println(ans+"");
	}

	boolean isLucky(int n){
		for(; n>0; n/=10){
			if(n%10!=4&&n%10!=7){
				return false;
			}
		}
		return true;
	}

	int[] p;

	void make(int n){
		p=new int[n];
		fill(p, -1);
	}

	int find(int x){
		return p[x]<0?x:(p[x]=find(p[x]));
	}

	boolean union(int x, int y){
		x=find(x);
		y=find(y);
		if(x!=y){
			if(p[y]<p[x]){
				int t=x;
				x=y;
				y=t;
			}
			p[x]+=p[y];
			p[y]=x;
		}
		return x!=y;
	}

	int size(int x){
		return -p[find(x)];
	}

	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){
		new E().run();
	}
}

■Result

ooo-o 4068pts. 27th
1631 -> 1689

Codeforces Beta Round #83 Div. 2 Only

Codeforces Beta Round #83 Div. 2 Only 8/24 0:00~2:00)

■A. Palindromic Times

問題

デジタル時計の時刻が与えられる(HH:MMの形式).
その時刻以降で,時刻が回文になるものを求めよ.

解法

高々24x60回の計算で終わるので,逐一試す.
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;

	void run(){
		String[] ss=sc.next().split(":");
		int h=Integer.parseInt(ss[0]);
		int m=Integer.parseInt(ss[1]);
		for(;;){
			if(++m==60){
				m=0;
				if(++h==24){
					h=0;
				}
			}
			String s=String.format("%02d:%02d", h, m);
			if(new StringBuffer(s).reverse().toString().equals(s)){
				println(s);
				return;
			}
		}
	}

	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){
		new A().run();
	}
}

■C. Dorm Water Supply

問題・解法

ある有向グラフが与えられる.
頂点には,多くとも1つの入る/出る辺があり,辺には情報として容量が与えられる.
以下を満たす(頂点V,頂点U,容量C)を求めよ.
  • Vには入る辺がない.
  • Uには出る辺がない.
  • Vから辺を辿ることで,Uに到着する.
  • Cは,VからUに至る辺の容量で最小のもの.
問題を意訳すると以上のようになるため,あとは書くだけです.
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 INF=1<<28;
	double EPS=1e-9;

	int n, p;
	E[] es;
	int[] parent;
	LinkedList<E> answers;
	boolean[] visited;

	class E{
		int from, to, cap;

		E(int from, int to, int cap){
			this.from=from;
			this.to=to;
			this.cap=cap;
		}
	}

	void run(){
		n=sc.nextInt();
		p=sc.nextInt();
		es=new E[n];
		answers=new LinkedList<E>();
		parent=new int[n];
		fill(parent, -1);
		for(int i=0; i<n; i++){}
		for(int i=0; i<p; i++){
			int a=sc.nextInt()-1;
			int b=sc.nextInt()-1;
			int d=sc.nextInt();
			es[a]=new E(a, b, d);
			parent[b]=a;
		}
		solve();
	}

	void solve(){
		visited=new boolean[n];
		for(int i=0; i<n; i++){
			if(visited[i]){
				continue;
			}
			int k=i;
			boolean loop=false;
			for(; parent[k]>=0;){
				k=parent[k];
				if(k==i){
					loop=true;
					break;
				}
			}
			if(loop){
				continue;
			}
			if(es[k]!=null){
				visited[k]=true;
				dfs(es[k].to, k, es[k].cap);
			}
		}
		E[] anss=answers.toArray(new E[0]);
		sort(anss, new Comparator<E>(){
			@Override
			public int compare(E e1, E e2){
				return e1.from-e2.from;
			}
		});
		println(anss.length+"");
		for(E e : anss){
			println(e.from+" "+e.to+" "+e.cap);
		}
	}

	void dfs(int v, int tank, int diameter){
		visited[v]=true;
		if(es[v]==null){
			answers.add(new E(tank+1, v+1, diameter));
			return;
		}
		dfs(es[v].to, tank, min(diameter, es[v].cap));
	}

	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){
		new C().run();
	}
}

■D. Basketball Team

問題

N人からなるチームを作りたい.
候補は全部でS人であり,Herr Wafaには仲間がK人いる.
S人からN人をランダムに選ぶとき,
Herr Wafaが少なくとも一人の仲間と一緒になる確率を求めよ.
N人を選べない(候補の人数が足りない)場合は-1とせよ.

解法

Herr Wafaがチームに選ばれなかった状態は省く.
(N, R)を二項係数(=N個からR個を選ぶ組み合わせの総数)とする.
Herr Wafaがチームに選ばれたとして,残りのN-1人を選ぶ方法は(S-1, N-1)通り.
その内,仲間が一人も居ない場合は(S-1-K, N-1)通り.すなわち,
1-{(S-1-K, N-1)/(S-1, N-1)}
が答え.
左の項はもっと簡単に,
(S-N)(S-N-1)…(S-N-K+1)
-----------------------
(M-1)(M-2)…(M+K)
と表せるので,ループ一つで求められる.
但し,精度が落ちないように工夫して計算する必要がある(下記コード参照).
import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;

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

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

	int INF=1<<28;
	double EPS=1e-9;

	int n, m, h;
	int[] s;

	void run(){
		n=sc.nextInt();
		m=sc.nextInt();
		h=sc.nextInt()-1;
		s=new int[m];
		for(int i=0; i<m; i++){
			s[i]=sc.nextInt();
		}
		solve();
	}

	void solve(){
		int sum=0;
		for(int i=0; i<m; i++){
			sum+=s[i];
		}
		if(sum<n){
			println("-1.0");
			return;
		}
		int k=s[h]-1;
		double ans=1;
		for(int i=0; i<k; i++){
			ans*=(double)(sum-n-i)/(sum-1-i);
		}
		println((1-ans)+"");
	}

	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){
		new D().run();
	}
}

■Result

oxoo- 2816pts. 78th
1562 -> 1631
次回でDiv.1に戻れるかも知れないがしかし….

2011年4月20日水曜日

Codeforces Beta Round #69 (Div. 2 Only)

Codeforces Beta Round #69 (Div. 2 Only)

Div. 1復帰が目標でした.

A. Panoramixs Prediction

値が小さいので愚直に一つずつ試行.
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 m, n;

 void run(){
  m=sc.nextInt();
  n=sc.nextInt();
  boolean f=true;
  for(int i=m+1; i<n; i++){
   f&=!isP(i);
  }
  f&=isP(n);
  println(f?"YES":"NO");
 }

 boolean isP(int n){
  for(int i=2; i*i<=n; i++){
   if(n%i==0){
    return false;
   }
  }
  return n!=1;
 }

 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){
  new A().run();
 }
}

B. Depression

%12を忘れないように気をつけるだけ.
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;

 void run(){
  String[] ss=sc.next().split(":");
  double h=Integer.parseInt(ss[0]);
  double m=Integer.parseInt(ss[1]);
  h=(h%12)/12.0*360;
  m=m/60.0*360;
  h=(h+m/12)%360;
  println(h+" "+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){
  new B().run();
 }
}

C. Heroes

全探索で解くことが出来るが,ちょっとしたミスをしたためSystem Test落ち.下は修正版.

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 INF=1<<28;
 double EPS=1e-9;

 int n, a, b, c;
 int[] p, q;
 HashMap<String, Integer> map;

 void run(){
  int m=7;

  map=new HashMap<String, Integer>();
  map.put("Anka", 0);
  map.put("Chapay", 1);
  map.put("Cleo", 2);
  map.put("Troll", 3);
  map.put("Dracul", 4);
  map.put("Snowy", 5);
  map.put("Hexadecimal", 6);

  n=sc.nextInt();
  p=new int[n];
  q=new int[n];
  for(int i=0; i<n; i++){
   p[i]=map.get(sc.next());
   sc.next();
   q[i]=map.get(sc.next());
  }
  a=sc.nextInt();
  b=sc.nextInt();
  c=sc.nextInt();

  long dmin=1L<<32;
  int lmax=0;
  for(int k=1; k<1<<m; k++){
   for(int j=1; j<1<<m; j++){
    int i=((1<<m)-1)&~(k^j);
    if((k^j)==(k|j)&&i>0){
     int x=a/Integer.bitCount(i);
     int y=b/Integer.bitCount(j);
     int z=c/Integer.bitCount(k);
     int d=max(abs(x-y), max(abs(y-z), abs(z-x)));

     int l=0;
     for(int e=0; e<n; e++){
      if(((k>>p[e])&1)!=0&&((k>>q[e])&1)!=0)
       l++;
      else if(((j>>p[e])&1)!=0&&((j>>q[e])&1)!=0)
       l++;
      else if(((i>>p[e])&1)!=0&&((i>>q[e])&1)!=0)
       l++;
     }
     if(d<dmin){
      dmin=d;
      lmax=l;
     }else if(d==dmin){
      lmax=max(lmax, l);
     }
    }
   }
  }
  println(dmin+" "+lmax);
 }

 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){
  new C().run();
 }
}

D. Falling Anvils

x2+√px+q=0は,p≧4qならば実解が存在する.
つまり,(p,q)∈[0,a]×[-b,b]の長方形内においてp≧4qを満たす領域の面積を計算し,それを長方形の面積で割った値が,実解が存在する確率.a=0やb=0の時は,0除算を避けるために例外処理を追加する必要がある.
import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;

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

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

 int INF=1<<28;
 double EPS=1e-9;

 int t;
 double a, b;

 void run(){
  t=sc.nextInt();
  for(int i=0; i<t; i++){
   a=sc.nextInt();
   b=sc.nextInt();
   double area;
   if(4*b<a+EPS){
    area=2*b*(a-b);
   }else{
    area=a*(b+a/8);
   }
   if(abs(b)<EPS){
    println("1");
   }else if(abs(a)<EPS){
    println("0.5");
   }else{
    println(area/(2*a*b)+"");
   }
  }
 }

 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){
  new D().run();
 }
}
ooxo- 2726p 46位
1624 -> 1654
復帰完了…というところです.

2011年3月8日火曜日

Codeforces Round #61 (Div. 2)

コンテストが随分ご無沙汰だったので参加してきました.

Codeforces Round #61 (Div. 2)

A. Petya and Java

面倒だったので,BigIntegerを使って読み込み.実は,入力は必ず正の数なので,負の方向へのチェックは必要ありませんでした….
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;

 void run(){
  BigInteger b=sc.nextBigInteger();
  long[] s={-128, -32768, -2147483648, -9223372036854775808L};
  long[] e={127, 32767, 2147483647, 9223372036854775807L};
  String[] ss={"byte", "short", "int", "long"};
  for(int i=0; i<4; i++){
   if(b.compareTo(new BigInteger(s[i]+""))>=0
     &&b.compareTo(new BigInteger(e[i]+""))<=0){
    println(ss[i]);
    return;
   }
  }
  println("BigInteger");
 }

 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){
  new A().run();
 }
}

B. Petya and Countryside

全探索すれば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 B{
 Scanner sc=new Scanner(System.in);

 int INF=1<<28;
 double EPS=1e-9;

 int n;
 int[] a;

 void run(){
  n=sc.nextInt();
  a=new int[n];
  for(int i=0; i<n; i++){
   a[i]=sc.nextInt();
  }
  int max=0;
  for(int j=0; j<n; j++){
   int s=1;
   for(int i=j-1; i>=0; i--){
    if(a[i]<=a[i+1]){
     s++;
    }else{
     break;
    }
   }
   for(int i=j+1; i<n; i++){
    if(a[i-1]>=a[i]){
     s++;
    }else{
     break;
    }
   }
   max=max(max, s);
  }
  println(max+"");
 }

 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){
  new B().run();
 }
}

C. Petya and File System

書けば通ると思いましたが,落ちてしまいました.

D. Petya and His Friends

私が考えたのは以下のやり方.
a1a2a3a4an
2222
3333
5555
7777

これを縦に掛けたものがそれぞれ答え.

実際には,6, 10, 15, 15*2, 15*3, …で十分だったようです.
import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;

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

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

 int INF=1<<28;
 double EPS=1e-9;

 void run(){
  int n=sc.nextInt();
  if(n==2){
   println("-1");
   return;
  }
  BigInteger[] bis=new BigInteger[n];
  for(int i=0; i<n; i++){
   bis[i]=BigInteger.ONE;
  }

  int max=1000;
  int p=0;
  int[] prime=new int[max];
  boolean[] isPrime=new boolean[max+1];
  Arrays.fill(isPrime, true);
  isPrime[0]=isPrime[1]=false;
  for(int i=2; i<=max; i++){
   if(isPrime[i]){
    prime[p++]=i;
    for(int j=2*i; j<=max; j+=i){
     isPrime[j]=false;
    }
   }
  }

  for(int j=0; j<n; j++){
   BigInteger bi=new BigInteger(prime[j]+"");
   for(int i=0; i<n-1; i++){
    bis[(j+i)%n]=bis[(j+i)%n].multiply(bi);
   }
  }
  for(int i=0; i<n; i++){
   if(bis[i].toString().length()>100){
    println("-1");
    return;
   }
  }
  for(int i=0; i<n; i++){
   println(bis[i]+"");
  }
 }

 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){
  new D().run();
 }
}
ooxo- 3226p 68位
1506 -> 1694
紫コーダーになりました.

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年8月18日水曜日

Codeforces Beta Round #26

Codeforces Beta Round #26 8/17(0:00~2:00)

今回は,TopCoderっぽいルール.
1.問題を解き.コードを提出.
2.Pretestsに通ったら,一先ず得点がもらえる.
3.そのコードに自信があったら"ロック"する.一度ロックしたら,コードを修正する事は出来ないし,ロックを解除する事も出来ない.
4.ロックした問題については,他の人のコードを見ることが出来る.
5.間違ってそうなコードがあったら,バグを誘発する入力を与える.撃墜できたら+100,ミスしたら-50.
これが競技中ずっと行われます.競技終了後,システムテストが行われます.
前回このルールで参加した時は,撃墜祭りでしたが,今回はそれ程でもありませんでした.

■A. Almost Prime
□問題
素因数が2種類の数をAlmost Primeという.n以下のAlmost Primeの個数を答えよ.
□解法
やるだけ.
□コード
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 n=sc.nextInt();
int[] cnt=new int[3001];
for(int i=2; i<=3000; i++){
cnt[i]+=cnt[i-1]+(isAP(i)?1:0);
}
println(""+cnt[n]);
}

boolean isAP(int n){
int d=-1, e=-1;
int m=n;
for(int i=2; i<n; i++){
if(m%i==0){
if(e!=-1){
return false;
}else if(d!=-1){
e=i;
}else{
d=i;
}
while(m%i==0)
m/=i;
}
}
return e!=-1;
}

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. Regular Bracket Sequence
□問題
(()))()(()(のような括弧列から,矛盾が無くなる様に括弧を取り除いた時,最大で何括弧残るか.
↑の場合(())()()となり答えは8.
□解法
左括弧が来たらカウンタ++,右括弧が来たらカウンタ--.カウンタが負になったらその分左括弧を取り除き,最終的にカウンタが正になったらその分右括弧を取り除く.
□コード
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);

void run(){
char[]cs =sc.nextLine().toCharArray();
int cnt=0;
int stack=0;
for(char c:cs){
if(c=='(')
stack++;
else{
if(stack==0)
cnt++;
else
stack--;
}
}
cnt+=stack;
int length=cs.length-cnt;
println(""+length);
}

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();
}
}


■C. Parquet
□問題
mxnの領域に1x2,2x1,2x2のタイルを敷き詰める問題.
□解法
m,nで場合わけして敷き詰めるだけ.実装ゲー.
□コード(適当でごめんなさい)
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, m, a, b, c;
char[][] map;

void run(){
n=sc.nextInt();
m=sc.nextInt();
a=sc.nextInt();
b=sc.nextInt();
c=sc.nextInt();
map=new char[n][m];
if((m*n)%2!=0){
println("IMPOSSIBLE");
return;
}
if(n%2==0&&m%2==0){
for(int j=0; j<n; j+=2){
for(int i=0; i<m; i+=2){
if(c>0){
c--;
char s=getDifferent(new int[]{i, i+1, i, i+1},
new int[]{j, j, j+1, j+1});
map[j][i]=map[j][i+1]=map[j+1][i]=map[j+1][i+1]=s;
}else if(a>=2){
char s=getDifferent(new int[]{i, i+1}, new int[]{j, j});
map[j][i]=map[j][i+1]=s;
char t=getDifferent(new int[]{i, i+1}, new int[]{j+1, j+1});
map[j+1][i]=map[j+1][i+1]=t;
a-=2;
}else if(b>=2){
char s=getDifferent(new int[]{i, i}, new int[]{j, j+1});
map[j][i]=map[j+1][i]=s;
char t=getDifferent(new int[]{i+1, i+1}, new int[]{j, j+1});
map[j][i+1]=map[j+1][i+1]=t;
b-=2;
}else{
println("IMPOSSIBLE");
return;
}
}
}
}
if(m%2==1){
for(int j=0; j<n; j+=2){
for(int i=0; i<m-1; i+=2){
if(c>0){
c--;
char s=getDifferent(new int[]{i, i+1, i, i+1},
new int[]{j, j, j+1, j+1});
map[j][i]=map[j][i+1]=map[j+1][i]=map[j+1][i+1]=s;
}else if(a>=2){
char s=getDifferent(new int[]{i, i+1}, new int[]{j, j});
map[j][i]=map[j][i+1]=s;
char t=getDifferent(new int[]{i, i+1}, new int[]{j+1, j+1});
map[j+1][i]=map[j+1][i+1]=t;
a-=2;
}else if(b>=2){
char s=getDifferent(new int[]{i, i}, new int[]{j, j+1});
map[j][i]=map[j+1][i]=s;
char t=getDifferent(new int[]{i+1, i+1}, new int[]{j, j+1});
map[j][i+1]=map[j+1][i+1]=t;
b-=2;
}else{
println("IMPOSSIBLE");
return;
}
}
}
for(int j=0; j<n; j+=2){
if(b>0){
char s=getDifferent(new int[]{m-1, m-1}, new int[]{j, j+1});
map[j][m-1]=map[j+1][m-1]=s;
b--;
}else{
println("IMPOSSIBLE");
return;
}
}
}
if(n%2==1){
for(int j=0; j<n-1; j+=2){
for(int i=0; i<m; i+=2){
if(c>0){
c--;
char s=getDifferent(new int[]{i, i+1, i, i+1},
new int[]{j, j, j+1, j+1});
map[j][i]=map[j][i+1]=map[j+1][i]=map[j+1][i+1]=s;
}else if(b>=2){
char s=getDifferent(new int[]{i, i}, new int[]{j, j+1});
map[j][i]=map[j+1][i]=s;
char t=getDifferent(new int[]{i+1, i+1}, new int[]{j, j+1});
map[j][i+1]=map[j+1][i+1]=t;
b-=2;
}else if(a>=2){
char s=getDifferent(new int[]{i, i+1}, new int[]{j, j});
map[j][i]=map[j][i+1]=s;
char t=getDifferent(new int[]{i, i+1}, new int[]{j+1, j+1});
map[j+1][i]=map[j+1][i+1]=t;
a-=2;
}else{
println("IMPOSSIBLE");
return;
}
}
}
for(int i=0; i<m; i+=2){
if(a>0){
char s=getDifferent(new int[]{i, i+1}, new int[]{n-1, n-1});
map[n-1][i]=map[n-1][i+1]=s;
a--;
}else{
println("IMPOSSIBLE");
return;
}
}
}
for(int j=0;j<n;j++){
for(int i=0;i<m;i++){
System.out.print(map[j][i]);
}
println("");
}

}

char getDifferent(int[] xs, int[] ys){
boolean[] exist=new boolean[256];
for(int i=0; i<xs.length; i++){
int x=xs[i];
int y=ys[i];
if(x>0)
exist[map[y][x-1]]=true;
if(x<m-1)
exist[map[y][x+1]]=true;
if(y>0)
exist[map[y-1][x]]=true;
if(y<n-1)
exist[map[y+1][x]]=true;
}
for(int i=0; i<exist.length; i++)
if(!exist[i]&&Character.isLowerCase(i))
return (char)i;
return '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();
}
}


■D. Tickets
確率問題は苦手…

■Result
○○○××
2626p
51位

■Rating
1744 -> 1851

現時点で92位.CodeforcesでならRedCoderを狙えるかも….

2010年8月2日月曜日

Codeforces Beta Round #24

Codeforces Beta Round #24 7/26(22:00~24:00)

■A. Ring road

□問題
n個の都市がある.
ある都市aiとある都市biの間には,一方通行の道路がある.
一方通行の向きを変えるには,ciのコストがかかる.
ある都市から他のn-1都市全てに辿れるよう一方通行の向きを変えたい.
最小コストはいくらか.

□解法
グラフが環になっているので,一方通行の流れを時計回り/反時計回りとする時のそれぞれのコストを計算し,小さい方を出力するだけ.一発AC.

# 実は反時計回りでのコストは,総コストから時計回りのコストを引くだけで計算できます.

□コード
import java.util.Scanner;

public class A{

Scanner sc=new Scanner(System.in);

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

public void run(){
n=sc.nextInt();
a=new int[n];
b=new int[n];
c=new int[n];
for(int i=0; i<n; i++){
a[i]=sc.nextInt();
b[i]=sc.nextInt();
c[i]=sc.nextInt();
}
int cost1=0;
boolean[] visited=new boolean[n];
visited[0]=true;
int p=b[0];
for(int k=1; k<n; k++){
for(int i=0; i<n; i++){
if(visited[i])
continue;
if(a[i]==p){
p=b[i];
visited[i]=true;
break;
}else if(b[i]==p){
cost1+=c[i];
p=a[i];
visited[i]=true;
break;
}
}
}
int cost=0;
for(int x : c)
cost+=x;
int cost2=cost-cost1;
println(""+Math.min(cost1, cost2));
}

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. F1 Champions

□問題
F1のレースがt回行われた.
最終順位のつけ方は以下の2種類の以下の優先度順に決める.
Original
勝ち点が大きい->1位になった回数が多い->2位になった回数が多い->…
Alternative rule
1位になった回数が多い->勝ち点が大きい->2位になった回数が多い->…
勝ち点は,1位から順に,25, 18, 15, 12, 10, 8, 6, 4, 2, 1, 0, ….
それぞれのルールでの最終順位が1位のドライバーの名前を出力せよ.

□解法
ソートするだけ.一発AC.

□コード
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Scanner;

public class B{

Scanner sc=new Scanner(System.in);

int m, n;
HashMap<String, R> map=new HashMap<String, R>();
int[] ps={25, 18, 15, 12, 10, 8, 6, 4, 2, 1};

public void run(){
m=sc.nextInt();
for(int i=0; i<m; i++){
n=sc.nextInt();
for(int k=0; k<n; k++){
String s=sc.next();
if(!map.containsKey(s))
map.put(s, new R(s));
R r=map.get(s);
if(k<ps.length)
r.score+=ps[k];
r.rank[k]++;
}
}

R[] rs=map.values().toArray(new R[0]);

Arrays.sort(rs, new Comparator<R>(){
@Override
public int compare(R r1, R r2){
if(r1.score!=r2.score)
return r2.score-r1.score;
for(int i=0; i<50; i++)
if(r1.rank[i]!=r2.rank[i])
return r2.rank[i]-r1.rank[i];
return 0;
}
});
println(rs[0].name);

Arrays.sort(rs, new Comparator<R>(){
@Override
public int compare(R r1, R r2){
if(r1.rank[0]!=r2.rank[0])
return r2.rank[0]-r1.rank[0];
if(r1.score!=r2.score)
return r2.score-r1.score;
for(int i=1; i<50; i++){
if(r1.rank[i]!=r2.rank[i])
return r2.rank[i]-r1.rank[i];
}
return 0;
}
});
println(rs[0].name);
}

final class R{
int score=0;
int[] rank=new int[50];
String name;

R(String name){
this.name=name;
}
}

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();
}

}


■C. Sequence of points

□問題
座標M0, A0, …, An-1が与えられる.
Miは,A(i-1)%nに関してMi-1と対称である.
Mjを計算せよ.

□解法
1≦j≦1018だと…?!
これは漸化式みたいにして解くのかな?
問題より,
Mi=2A(i-1)%n-Mi-1
だから…(弄る
周期2nになった.j%2nでOKではないですか.
ついでにi=0~2n-1についての(一応)閉じた式が計算できたの実装.
一発AC.

# 無駄に頑張りましたが,実は,閉じた式なんか要らなくて,周期2nと分かった時点で上の漸化式もどきからM0, …, M2n-1を生成すれば良かったのでした.

□コード
import java.util.Scanner;

public class C{

Scanner sc=new Scanner(System.in);

int n;
long j;

public void run(){
n=sc.nextInt();
j=sc.nextLong();
int[] mx=new int[2*n];
int[] my=new int[2*n];
mx[0]=sc.nextInt();
my[0]=sc.nextInt();
int[] ax=new int[n];
int[] ay=new int[n];
for(int i=0; i<n; i++){
ax[i]=sc.nextInt();
ay[i]=sc.nextInt();
}
for(int i=1; i<2*n; i++){
mx[i]=2*ax[(i-1)%n]-mx[i-1];
my[i]=2*ay[(i-1)%n]-my[i-1];
}
int k=(int)(j%(2*n));
println(mx[k]+" "+my[k]);
}

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
○○○××

■Rating
1633 -> 1744

大幅に上昇.今回は割と調子が良かったです.

2010年7月11日日曜日

Codeforces Beta Round #23

Codeforces Beta Round #23(7/9 0:00~2:00)

■A. You're Given a String...

□問題
文字列が与えられる.文字列中に2回以上現れる部分文字列の内,最大の長さを求めよ.

□解法
文字列の長さが100以下なので書くだけ.

□コード
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(){
String s=sc.nextLine();
int n=s.length();
int ans=0;
for(int len=1; len<n; len++){
for(int i=0; i+len<=n; i++){
String t=s.substring(i, i+len);
if(s.indexOf(t, i+1)!=-1){
ans=len;
break;
}
}
}
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 A().run();
}
}

■B. Party

□問題
N人がパーティにやってきた.最初に友達が0人の人が省かれる.次に現在いるパーティ内での友達が1人の人が省かれる,次に現在いるパーティ内での友達が2人の人が省かれる,…最後に現在いるパーティ内での友達がN-1人の人が省かれる.最後まで残った人の数が最大のものを求める.

□解法
問題の趣旨が掴めない….
→しかし,結構な人数の人が提出している.
→よく分からないけど,実は答え全部1なんじゃね?
→提出,WA,あわわわわ.
→試しに,N=3で手書きシミュレートしてみよう.
→なるほど,2人以上が残ることは出来ないなぁ.
→N=4で(ry
→最大2人残った.
→あぁ,N>=2の時は最大N-2人残るのか(N<2の時は0人).
→提出,AC.

□コード
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);

void run(){
int t=sc.nextInt();
for(int i=0; i<t; i++){
int n=sc.nextInt();
println(""+max(0, n-2));
}
}

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();
}

}

C,D,Eは解けませんでした….

■Result
○○×××

■Rating
1554 -> 1633

CDEのどれかを解くことが出来れば安定して上昇すると思われます.

2010年6月27日日曜日

Codeforces Beta Round #19

Codeforces Beta Round #17(6/25 0:00~2:00)
悪夢再び….

■A World Football Cup

□問題
nチームのリーグ戦の結果から,上位n/2チームを辞書式順に出力せよ.

□解法
ソートするだけ.

□コード
import java.util.*;

public class A{
Scanner sc=new Scanner(System.in);
HashMap<String, Integer> map=new HashMap<String, Integer>();
Team[] teams;

void run(){
int n=sc.nextInt();
sc.nextLine();
teams=new Team[n];
for(int i=0; i<n; i++){
String s=sc.nextLine();
map.put(s, i);
teams[i]=new Team();
teams[i].name=s;
}

for(int i=0; i<n*(n-1)/2; i++){
String[] s=sc.nextLine().split(" ");
String[] team=s[0].split("-");
String[] score=s[1].split(":");
int t1=map.get(team[0]);
int t2=map.get(team[1]);
int s1=Integer.parseInt(score[0]);
int s2=Integer.parseInt(score[1]);
if(s1>s2){
teams[t1].point+=3;
}else if(s1<s2){
teams[t2].point+=3;
}else{
teams[t1].point+=1;
teams[t2].point+=1;
}
teams[t1].diff+=s1-s2;
teams[t2].diff+=s2-s1;
teams[t1].goal+=s1;
teams[t2].goal+=s2;
}

Arrays.sort(teams, new java.util.Comparator<Object>(){
@Override
public int compare(Object o1, Object o2){
Team t1=(Team)o1;
Team t2=(Team)o2;
if(t1.point!=t2.point)
return t2.point-t1.point;
if(t1.diff!=t2.diff)
return t2.diff-t1.diff;
return t2.goal-t1.goal;
}
});

String[] s=new String[n/2];
for(int i=0;i<n/2;i++)
s[i]=teams[i].name;
Arrays.sort(s);
for(int i=0;i<n/2;i++)
System.out.println(s[i]);
}

class Team{
String name;
int point;
int diff;
int goal;
}

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


そして,B,C,D,Eはどれ一つとして解けませんでした,無念….

・Result
○××××

・Rating
1580 -> 1554

残念な結果です.

2010年6月12日土曜日

Codeforcesへの参加方法(2011/9/23更新)

今回はCodeforcesへの参加方法について.

■登録方法

http://www.codeforces.com/registerにアクセス.



Handle
ハンドルネーム(例:todo)
Email
メールアドレス(例:hoge@gmail.com)
Password
パスワード(例:hogehoge)
Confirm Password
パスワード確認(上に同じ)

これらを入力した後,Registerで完了します. ちなみに,Gmailアカウントを持っている方は,Use Gmailをクリックすれば,それだけで登録が完了します(多分).

■コンテストの登録

近々コンテストがある場合は, トップページhttp://www.codeforces.com/
→ Pay attention
Registration is running
Codeforces Beta Round #18 (Div. 2 Only)
119:34:50
Register now »

こんな感じにコンテストのお知らせが常時表示されます. 登録は,Register nowをクリックするだけです. 開始までの時間が表示されているので便利.

■コンテストの流れ

Registerした状態で開始時刻になると,色々とダイアログが出て,コンテストが開始されます.
基本的には,120分で5問を解くことになります. 問題のそれぞれには,問題文とサンプルがあります. 入出力が標準入出力なので,慣れてない人は少し面倒かもしれません.
コードが完成したら,SUBMITから提出します. 初期のコンテストとは方針が変わり,まず,Pretest(テストケースが弱い)が行われます. これに通れば,ひとまず得点が与えられます. プレテスト通過後,Lock(鍵掛け)を行うことができます. ある問題をLockすると,自分は(その問題の)回答をResubmitできなくなりますが, その代わりとして他人のコードを見ることができます. ある人のコードが間違っていると思った場合は,バグを誘発するような入力を与えます(Hack). 成功すれば+100,失敗すれば-50ポイント得点が変動します. ちなみに,自分の回答がHackされた場合は, その問題の得点が失われますが, (Lockしていないならば)再びコードを提出することができます.
コンテスト終了後は,System Test(厳密なテストケース)が行われ, このテストに通れば,最終的に得点が与えられす.

Codeforces Beta Round #17

Codeforces Beta Round #17(6/11 0:00~2:00)

時間的な都合でしばらくはTopCoderに参加できないので,Codeforcesに参加してきました.
Codeforcesは,SRM(TopCoder)のようなプログラミングコンテストの一つで,形式はICPCに近い感じです.SRMと違うと感じた点は,

・SRMが3問75分であるのに対し,Codeforcesは基本的に5問120分.
・SRMのように参加者をルーム毎に分けない.
・データの受け渡しには標準入出力を使う
・コードを提出したら,即座にシステムテストが行われる.また,テストに落ちても再提出できる.
・↑のため,Challenge PhaseやSystem Testが無い.

といった所です.

A Noldbach problem
正整数kとnが与えられる.2からnまでの素数で,
1+(i番目の素数)+(i+1番目の素数)
という形で表現出来るものがk個以上ある場合は"Yes",そうでない時は"No"と出力せよ.

値の範囲が,2≦n≦1000,0≦k≦1000と狭かったため,簡単な実装ゲーでした.

import java.util.*;

public class A{

void exe(){
LinkedList<Integer> list=new LinkedList<Integer>();
for(int i=2; i<=1000; i++)
if(isPrime(i))
list.add(i);
Object[] primes=list.toArray();

Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int k=sc.nextInt();
int cnt=0;
for(int c=2; c<=n; c++){
if(!isPrime(c))
continue;
for(int i=0; i<primes.length-1; i++){
int p1=(Integer)primes[i];
int p2=(Integer)primes[i+1];
if(c==1+p1+p2){
cnt++;
}
}
}
if(cnt>=k)
System.out.println("YES");
else
System.out.println("NO");
}

boolean isPrime(int n){
if(n<=1)
return false;
if(n==2)
return true;
if(n%2==0)
return false;
int m=(int)Math.sqrt(n)+1;
for(int i=3; i<=m; i+=2)
if(n%i==0)
return false;
return true;
}

public static void main(String[] args){
Locale.setDefault(Locale.US);
new A().exe();
}
}


B Hierarchy
Nickの会社では,n人の従業員を雇用している.
Nickは,従業員の階層構造を作るため,1人を除いたn-1人の従業員に対し,それぞれ1人の監督者を設けることにした.
従業員aiが,従業員biの監督者となる時の費用をciとした時,
ai bi ci
の組がm個与えられる.
階層構造を作ったとき,最小のコストを計算せよ.

実際に木構造を作って階層構造を再現する必要があるかなと思いましたが,そんな必要ありませんでした.

import java.util.*;

public class B{
int n, m;
int[] q, a, b, c;

void exe(){
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
q=new int[n];
for(int i=0; i<n; i++)
q[i]=sc.nextInt();
m=sc.nextInt();
a=new int[m];
b=new int[m];
c=new int[m];
for(int i=0; i<m; i++){
a[i]=sc.nextInt();
b[i]=sc.nextInt();
c[i]=sc.nextInt();
}
int max=0;
for(int i=0; i<n; i++){
if(q[i]>q[max])
max=i;
}
int cost=0;
for(int i=0; i<n; i++){
if(i==max)
continue;
int minj=-1;
for(int j=0; j<m; j++){
if(b[j]-1==i){
if(minj==-1||c[j]<c[minj]){
minj=j;
}
}
}
if(minj==-1){
System.out.println("-1");
return;
}
cost+=c[minj];
}
System.out.println(""+cost);
}

public static void main(String[] args){
Locale.setDefault(Locale.US);
new B().exe();
}
}


C Balance
文字列が与えられて,ごにょごにょ操作し,ある条件を満たす物は幾つ出来るかといった内容.

組み合わせ問題は苦手ですので,飛ばしました….
\(^o^)/

D Notepad
b進数でn桁の数を,1ページあたりc個書いた時,一番最後のページには幾つの数字が書かれているか?

最終的には,
bn-bn-1 mod c
を求めるという問題に還元出来ましたが,
2≦b<10106, 1≦n<10106, 1≦c<109
という条件に阻まれました.
\(^o^)/

E Palisection
\(^o^)/

・Result
○○×××

D問題が解ければ良かったのですが….

・Rating
0->1580

初挑戦でしたが,無事Div1に昇格する事が出来ました.