ACPC freshmen training
http://w.atwiki.jp/icpctrain/
ACPC freshmen training
ja
2013-11-16T21:43:52+09:00
1384605832
-
AOJ 1132 Circle and Points
https://w.atwiki.jp/icpctrain/pages/43.html
*AOJ1132 Circle and Points
**解説
***解法1
任意の二点を選んでその点を通る円を作る。円は2個ある。
そのような全ての円それぞれが包含できる点の数を数えて最大値を求める。N<=300なので間に合う。
円の中心点の求め方
選んだ2点a, bの作る直線Aの生む垂直二等分線と、2点のうち一方の点と中心を結ぶ長さ1の線分から、三平方の定理でAと中心の距離を求める。
後は、線分abの中点からaまたはbに向かうベクトルを90度回転してやれば、その位置が円の中心となる。
点を包含できるかの判定方法は、ベクトルを用いて円の中心を始点と考えた時の点までの長さと半径の比較で判定できる。
2013-11-16T21:43:52+09:00
1384605832
-
Geometry
https://w.atwiki.jp/icpctrain/pages/42.html
*Geometry
**Circle And Points
-[[AOJ 1132 Circle and Points]]
2013-11-16T21:41:22+09:00
1384605682
-
vector
https://w.atwiki.jp/icpctrain/pages/41.html
*vector
**swap
vectorの中身を全て交換する
>||
void swap( vector &from );
Ex.
vecA.swap(vecB);
||<
2013-11-10T13:44:14+09:00
1384058654
-
algorithm
https://w.atwiki.jp/icpctrain/pages/39.html
*algorithm
**next_permutation
stringや他のコンテナの全ての順列を生成する。
>||
#include <algorithm>
...
string str = "ABCDEF";
do {
cout << str << endl;
} while(next_permutation(str.begin(), str.end()));
Result:
ABCDEF
ABCDFE
ABCEDF
ABCEFD
...
FEDCBA (計 6! = 720個の文字列を生成)
||<
2013-11-02T03:42:52+09:00
1383331372
-
繰り返し二乗法
https://w.atwiki.jp/icpctrain/pages/38.html
*繰り返し二乗法
**解説
0を含むすべて自然数は2のべき乗の和の組み合わせで表すことが出来る。2進数がその例である。
nを2のべき乗の和で表すと
>||
n = 2^(k_1) + 2^(k_2) + 2^(k_3) + ...
||<
よって、
>||
x^n = x^(2^k_1) x^(2^k_2) x^(2^k_3) ...
||<
2進数で操作をすればよいので1のビットが立つ部分iについて、resにx^iを掛けていく。
下位ビットから考えているのでxは順次二乗していけばよい。nの1と0のビットの数だけ処理するのみなのでO(log n)でxのべき乗を高速に求められる。
>||
typedef long long ll;
ll mod_pow(ll x, ll n, ll mod) {
ll res = 1;
while(n > 0) {
if(n & 1) res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
||<
2013-11-02T03:10:04+09:00
1383329404
-
RMQ
https://w.atwiki.jp/icpctrain/pages/37.html
*RMQ ( RangeMinumumQuery )
**
2013-11-01T23:11:42+09:00
1383315102
-
AOJ0202 At Boss's Expense
https://w.atwiki.jp/icpctrain/pages/36.html
*AOJ0202 At Boss's Expense
**サイト
[http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0202]
**解説
上限金額が決まっていて、与えられた料理の金額を使ってそれぞれ0個以上用いて割り切れない最大の金額を求める。
「割り切れない」はすなわちその値が素数であることを示す。
「割り切れない」の意味が分かったので、取り敢えず「割り切れない」は横において、今度は問題の残りの部分の解釈に移る。
それぞれの料理を使う個数を決めて上限の金額を超えるまで全探索することはとてもできない。
添字が上限金額まで記憶可能なbool型の配列を用意して可能な合計金額をマーキングをしていこう。ある料理の値段を用いて新しくマークを付けるとき、既知のマークを始点としてある料理の金額分先にマーキングできる。初期条件としては合計金額が0円である自明なマーキングがある。
あとははじめの「割り切れない=素数である」をと合わせてマーキングされた中で答えになりうる最大の金額を見つければ良い。
>||
c[0] = 1;
for(int i=0; i<n; i++) {
cin >> b;
for(int j=b; j<MAX; j++) {
c[j] = c[j] | c[j-b];
}
}
int mx = -9999;
for(int i=0; i<=a; i++) {
if(c[i] && is_prime[i]) mx = max(mx, i);
}
if(mx == -9999) cout << "NA" << endl;
else cout << mx << endl;
||<
2013-11-01T22:56:55+09:00
1383314215
-
AOJ0557 A First Grader
https://w.atwiki.jp/icpctrain/pages/35.html
*AOJ0557 A First Grader
**サイト
[http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0557]
参考サイト
[http://d.hatena.ne.jp/Respect2D/20110212/1297501157]
[https://speakerdeck.com/kagamiz/aoj-0557-a-first-grader-jie-shuo]
**解説
+と-の2択を選びつつ様々な制限の元ansに一致する場合数を列挙します。
2択で処理を進めるので全探索するとO(2^n)です。取りあえず再帰で全探索コードを考えてみましょう。
数列の今見ている項とそこまでの計算結果の2つの状態が必要です。
終了条件でansと計算結果が一致していれば場合の数が1つ生じます。以下のコード上では例外処理が省略されています。
>||
int rec(int index, int sum) {
if(index == tail) return sum == ans;
return rec(index+1, sum + seq[index+1]) + rec(index+1, sum - seq[index+1]);
}
||<
同じ項を見ているときそこまでの計算結果も同じなら、その後の計算にダブりが生じます。何度も同じ計算をしないよう、計算結果の再利用をしましょう。メモ化再帰です。
>||
int rec(int index, int sum) {
if(memo[index][sum] != -1) return memo[index][sum];
if(index == tail) return sum == ans;
return memo[index][sum] = rec(index+1, sum + seq[index+1]) + rec(index+1, sum - seq[index+1]);
}
||<
これで無駄な計算が無くなり、O(ns) 100*21 = 2100通りとなりました。
再帰を考えることでindexやsumという状態を持つことが分かったので今度はDPしてみましょう。高校数学の漸化式のと同
2013-11-01T22:44:42+09:00
1383313482
-
AOJ1166 Amazing Mazes
https://w.atwiki.jp/icpctrain/pages/34.html
*AOJ1166 Amazing Mazes
**サイト
[http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1166&lang=jp]
**解説
渾身のギャグの問題です。
入力を理解しましょう。1と0は壁の存在の有無を示しています。
>||
1
0 1
0
1 0
||<
この入力において、1行目は縦に壁があること、2行目は横に壁がない・あるが連続すること、3行目は縦に壁がないこと、4行目は横に壁がある・ないが連続すること、5行目は縦に壁があること、を示します。
マップ全体を覆う壁は存在が自明なので入力に現れていないことに注意する必要があります。
図を描くと一発で理解できますが面倒で描いてません(クソ)
入力を理解したらそのデータを配列に格納します。取りあえず2つの方式を挙げます。
>>
3次元配列では、wall[四方向][今いるy座標][今いるx座標] = 1(通行可能) | 0(通行不可)
4次元配列では、pass[ny][nx][今いるy座標][今いるx座標] = 1(通行可能) | 0(通行不可)
<<
とすれば良いでしょう。問題の制約が高さも幅も2以上30以下であるので、4次元配列を作っても解けます。メモリは食いますがわかりやすいです。
2013-10-31T02:53:09+09:00
1383155589
-
AOJ1155 How can I satisfy thee? Let me count the ways...
https://w.atwiki.jp/icpctrain/pages/33.html
*AOJ1155 How can I satisfy thee? Let me count the ways...
**サイト
[http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1155&lang=jp]
**問題俯瞰
問題は与えられた式をある規則によって計算した結果が2となるときのP, Q, Rの組み合わせ数を答えるものです。
P, Q, Rは0, 1, 2とそれぞれ値が変化するので3重ループのfor文で回して27通り試しそのたびに構文解析をし直せばよいです。
Sample Inputが 2 であり、その結果 27 を返すものがあります。これはP, Q, Rがそれぞれいかなる値でも常に計算結果が2であるのでP, Q, Rの組み合わせ数は27通りということを示します。
**解説
以下の与えられたBNF((BNF = バッカス・ナウア記法(Backus-Naur form)といいます。2人の人の名前をつなげてます))に従って再帰的下向き構文解析のコードを書くのみです。
>||
<formula> ::= 0 | 1 | 2 | P | Q | R |
-<formula> | (<formula>*<formula>) | (<formula>+<formula>)
||<
電卓のときは<expression> <term> <factor>というように3つの要素がありましたが、今度は<formula>のみなので作る再帰関数もformula()のみ存在すれば必要十分です。
参考文献 → [https://gist.github.com/draftcode/1357281:title=構文解析 Howto]
さて、先に与えられた表の計算の仕組みを考えなければなりません。
XやY(この場合それぞれ<formula>)があるときに与えられている真理表において -X, (X*Y), (X+Y) はどのような仕組みで行われているでしょうか。
パターン数が少ないので演算の関係をすべて配列に埋め込んで条件分岐させて解いても良いですが、ちょっと格好良く(?)やりたいところです。
-X は 0が2, 1が1, 2が0 となります。if文を3つ書
2013-11-13T17:09:47+09:00
1384330187