#include<iostream>

using namespace std;

int main() {
	long long int a, b, c, d, m, i;
	while (cin >> a >> b) {
		for (i = 0;i < b;i++) {
			for (m = 0;m < a;m++) {
				if (a*(i + 1) == b*(m + 1)) {
					c = a*(i + 1);
					i = -1;
					break;
				}
			}
			if (i == -1) { break; }
		}
		if(a > b){
			for (i = a;i > 0;i--) {
				if (a%i == 0 && b%i == 0) { break; }
			}
		}else{
			for (i = b;i > 0;i--) {
				if (b%i == 0 && a%i == 0) { break; }
			}
		}
		d = i;
		cout << d << ' ' << c << endl;
	}
	return 0;
}

Global OOD problem IDs are disjoint from train, validation, and in-distribution test problem IDs.

GCD and LCM

Write a program which computes the greatest common divisor (GCD) and the least common multiple (LCM) of given a and b.

Input

Input consists of several data sets. Each data set contains a and b separated by a single space in a line. The input terminates with EOF.

Constraints

0 < a, b ≤ 2,000,000,000

LCM(a, b) ≤ 2,000,000,000

The number of data sets ≤ 50

Output

For each data set, print GCD and LCM separated by a single space in a line.

Sample Input

8 6
50000000 30000000

Output for the Sample Input

2 24
10000000 150000000

Submitted source-code file size, in bytes.

Execution CPU time reported by official Project CodeNet metadata, in milliseconds.

Peak memory usage reported by official Project CodeNet metadata, in kilobytes.


#include<iostream>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef pair<int,int> P;
typedef struct{
	int next;
	int cost[2];
}edge;

int n,m;
vector<edge> mapp[111];
int bfs(int now,int goal,int k);

int main(){
	while(1){
		cin >> n >> m;
		if(n == 0 && m == 0) break;
		for(int i=0;i<m+1;i++){
			mapp[i].clear();
		}
		for(int i=0;i<n;i++){
			int a,b,cost,tim;
			cin >> a >> b >> cost >> tim;
			edge x;
			x.next = a; x.cost[0] = cost; x.cost[1] = tim;
			mapp[b].push_back(x);
			x.next = b; x.cost[0] = cost; x.cost[1] = tim;
			mapp[a].push_back(x);
		}
		int k;
		cin >> k;
		int ans;
		for(int i=0;i<k;i++){
			int p,q,r;
			cin >> p >> q >> r;
			if(r == 0) ans = bfs(p,q,r);
			else if(r == 1) ans = bfs(p,q,r);
			cout << ans << endl;
		}
	}
}

int bfs(int now,int goal,int k){
	vector<int> min_cost;
	min_cost.resize(m+1,-1);
	priority_queue<P, vector<P>,greater<P> > que;
	que.push(P(0,now));
	min_cost[now] = 0;
	while(!que.empty()){
		P p = que.top(); que.pop();
		int no = p.second;
		int co = p.first;
		if(no == goal) return co;
		if(co > min_cost[no]) continue;
		int len=mapp[no].size();
		for(int i=0;i<len;i++){
			edge x = mapp[no][i];
			if(min_cost[x.next] == -1 || co+x.cost[k]<min_cost[x.next]){
				min_cost[x.next] = co + x.cost[k];
				que.push(P(co+x.cost[k],x.next));
			}
		}
	}
	return min_cost[goal];
}

青春の片道切符

太郎君は夏休みに電車で長旅をする計画を立てています。しかし高校生の身である太郎君が一ヵ月しかない夏休みで可能な限り遠くに旅をするには、出来るだけ安い行き方と出来るだけ早い行き方をそれぞれ見つけなければうまく計画が立てられません。太郎君が素敵な旅を満喫できるように、太郎君の計画の助けになるプログラムを作ってあげましょう。

線路の情報、駅の数を入力とし、問い合わせに応じて、最小金額または最短時間を出力するプログラムを作成してください。

Input

複数のデータセットの並びが入力として与えられます。入力の終わりはゼロふたつの行で示されます。各データセットは以下の形式で与えられます。

n m
a1 b1 cost1 time1
a2 b2 cost2 time2
:
an bn costn timen
k
p1 q1 r1
p2 q2 r2
:
pk qk rk

1 行目に線路の情報の数 n (1 ≤ n ≤ 3000)と駅の数 m (1 ≤ m ≤ 100) が与えられます。

続く n 行に i 番目の路線の情報が与えられます。各路線の情報として、路線がつなぐ２つの駅の番号 ai, bi (1 ≤ ai, bi ≤ m)、料金 costi (1 ≤ costi ≤ 1000)、移動時間 timei (1 ≤ timei ≤ 1000) が与えられます。ただし、各駅は 1 から m まで順番に番号が付けられているものとします。
なお、ai と bi が線路でつながっていれば、ai から bi、 bi からai の両方の移動が同じ料金と時間で可能とします。

続く行に問い合わせの数 k (1 ≤ k ≤ 200) が与えられます。続く k 行に i 番目の問い合わせが与えられます。各問合わせとして、出発駅 pi 、到着駅 qi 、出力する値の種類 ri (0 または 1)が与えられます。なお、問い合わせには必ず経路があるものとします。

データセットの数は 50 を超えない。

Output

データセットごとに、最小金額もしくは最短時間を１行に出力します。ri が 0 の時は最小金額を、 1 の時は最短時間を出力します。

Sample Input

6 5
1 2 200 10
1 4 400 15
1 3 250 25
2 4 100 10
4 5 150 20
3 5 300 20
2
1 5 0
1 5 1
0 0

Output for the Sample Input

450
35


# define _CRT_SECUREj_NO_WARNINGS 1
# define _USE_MATH_DEFINES
# include <iostream>
# include <numeric>
# include <string>
# include <bitset>
# include <vector>
# include <algorithm>
# include <cstdlib>
# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iomanip>
# include <queue>
# include <sstream>
# include <climits>
# include <cmath>
# include <list>
# include <functional>
# include <string>
# include <ctime>
# include <set>
# include <forward_list>
# include <map>
# include <stack>
using namespace std;
# define INF ((int)(1<<25))
# define REP(i,n) for(int i=0;i<(int)n;i++)
# define FOR(i,n) REP(i,n)
# define TORAD 2.0*M_PI/360.0
# define INT(x) int x;cin>>x;
# define ALL(x) (x).begin(),(x).end()
# define RALL(x) (x).rbegin(),(x).rend()
# define DEBUG(x) cout<<#x<<" :"<<x<<endl;
# define EPS 1e-12
template<class T> void debug(T a) { for (auto iiiiiiiiii : a)cout << iiiiiiiiii << endl; }
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int, int> pii;
typedef pair<int, pii> piii;
int dx[4] = { 0,1,0,-1 }, dy[4] = { -1,0,1,0 };

signed main()
{
	int n;
	while (cin >> n&&n)
	{
		int ans = 0;
		bool ok = false;
		FOR(i, n)
		{
			INT(x);
			if (x > 1)ok = true;
			if(x)ans++;
		}
		if (ok)cout << ans+1 << endl;
		else cout << "NA" << endl;
	}
}

おそろいの景品

ジョウ君とヤエさんは仲の良いカップルです。ジョウ君はカプセル玩具自販機(ガチャポン)の景品を集めており、二人で出かけたときも、ガチャポンを見つけると何度かやってみるほどの熱の入りようです。ヤエさんは楽しそうなジョウ君をそばで見ているだけでしたが、ジョウ君の今度の誕生日プレゼントにガチャポンの景品をひとつあげることにしました。ヤエさんはガチャポン自体にはあまり興味がわきませんでしたが、できればジョウ君とおそろいの景品が欲しいと思っています。

ヤエさんがやってみようと思うガチャポンは、１回のチャレンジで景品がひとつ出ます。品切れのものも含め景品が何種類あるのかと、それぞれの景品がいくつ残っているのかはわかります。しかし、1回のチャレンジでどの景品が出るかはわかりません。そこで、景品が出る順番にかかわらず、ヤエさんが同じ景品を必ず２つ得るために最低限必要なチャレンジの回数を出力するプログラムを作成してください。

入力

入力は複数のデータセットからなる。入力の終わりはゼロ1つの行で示される。各データセットは以下の形式で与えられる。

N
k1 k2 ... kN

各データセットは2行であり、1行目に景品が何種類あるかを表す整数N(1 ≤ N ≤ 10000)が与えられる。続く1行に各景品がいくつ残っているのかを表す整数ki(0 ≤ ki ≤ 10000)が与えられる。

データセットの数は100を超えない。

出力

データセットごとに、同じ景品を必ず２つ得るために最低限必要なチャレンジの回数を出力する。ただし、不可能な場合はNAと出力する。

入力例

2
3 2
3
0 1 1
1
1000
0

出力例

3
NA
2

１つ目のデータセットでは、運良く１種類目か２種類目の景品が連続で出て２回で済む可能性はあるが、同じ種類の景品を必ず２つ得るためには３回チャレンジする必要がある。

２つ目のデータセットでは、２つ以上残っている景品がもともと無いので不可能である。

３つ目のデータセットでは、景品は１種類だけなので２回のチャレンジでその景品が必ず２つ得られる。


#include<cstdio>
#include<cstring>
int  hyou[16][16],A,B;

int solve(int a,int b){
	if(hyou[a][b]==-1) return 0;
	if(a==0 || b==0) return 1;
	return solve(a-1,b)+solve(a,b-1);
}
int main(){
	int n,a,b;
	scanf("%d%d",&A,&B);
	if(A==0&&B==0)	return 0;
	memset(hyou,0,sizeof(hyou));
	scanf("%d",&n);
	while(n--){
		scanf("%d%d",&a,&b);
		hyou[a-1][b-1]=-1;
	}
	printf("%d\n",solve(A-1,B-1));
	main();
}

通学経路

問題

太郎君の住んでいるJOI市は，南北方向にまっすぐに伸びる a 本の道路と，東西方向にまっすぐに伸びる b 本の道路により，碁盤の目の形に区分けされている．

南北方向の a 本の道路には，西から順に 1, 2, ... , a の番号が付けられている．また，東西方向の b 本の道路には，南から順に 1, 2, ... , b の番号が付けられている．西から i 番目の南北方向の道路と，南から j 番目の東西方向の道路が交わる交差点を (i, j) で表す．

太郎君は，交差点 (1, 1) の近くに住んでおり，交差点 (a, b) の近くのJOI高校に自転車で通っている．自転車は道路に沿ってのみ移動することができる．太郎君は，通学時間を短くするため，東または北にのみ向かって移動して通学している．

現在， JOI市では， n 個の交差点 (x1, y1), (x2, y2), ... , (xn, yn) で工事を行っている．太郎君は工事中の交差点を通ることができない．

太郎君が交差点 (1, 1) から交差点 (a, b) まで，工事中の交差点を避けながら，東または北にのみ向かって移動して通学する方法は何通りあるだろうか．太郎君の通学経路の個数 m を求めるプログラムを作成せよ．

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．入力はゼロを２つ含む行で終了する．

1行目には，空白を区切りとして2個の整数 a, b が書かれている．これは，南北方向の道路の本数と，東西方向の道路の本数を表す． a, b は 1 ≤ a, b ≤ 16 をみたす．

2行目には, 工事中の交差点の個数を表す整数 n が書かれている． n は 1 ≤ n ≤ 40 をみたす．

続く n 行 (3行目から n+2 行目) には，工事中の交差点の位置が書かれている． i+2 行目には空白で区切られた整数 xi, yi が書かれており，交差点 (xi, yi) が工事中であることを表す． xi, yi は 1 ≤ xi, yi ≤ 16 をみたす．

データセットの数は 5 を超えない．

出力

データセットごとに, 太郎君の通学経路の個数 m を1行に出力する．

入出力例

入力例

5 4
3
2 2
2 3
4 2
5 4
3
2 2
2 3
4 2
0 0

出力例

5
5

下図は a=5, b=4, n=3 で，工事中の交差点が (2,2), (2,3), (4,2) の場合を表している．

この場合，通学経路は m=5 通りある． 5通りの通学経路を全て図示すると，以下の通り．

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。


#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <array>
#include <queue>
#include <algorithm>
#include <utility>
#include <cmath>
#include <map>

#define INF_LL 9000000000000000000
#define INF 2000000000

#define REP(i, n) for(int i = 0;i < (n);i++)
#define FOR(i, a, b) for(int i = (a);i < (b);i++)

using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

class Union_find{
private:
	vector<int> par;
	vector<int> rank;
	int n;

public:
	Union_find(int a){
		n = a;
		for(int i = 0;i < n;i++){
			par.push_back(i);
			rank.push_back(0);
		}
	}

	int find(int x){
		if(par[x] == x){
			return x;
		}else{
			return par[x] = find(par[x]);
		}
	}

	void unite(int x, int y){
		x = find(x);
		y = find(y);
		if(x == y) return;

		if(rank[x] < rank[y]){
			par[x] = y;
		}else{
			par[y] = x;
			if(rank[x] == rank[y]) rank[x]++;
		}
	}

	bool same(int x, int y){
		return find(x) == find(y);
	}
};

struct edge{int to, cost; };

int main(void){
	int m;
	while(cin >> m && m){
	int tx[200], ty[200];
	int n;
	map<int, vector<int> > S;
	REP(i, m){
		cin >> tx[i] >> ty[i];
	}
	cin >> n;
	REP(i, n){
		int x, y;
		cin >> x >> y;
		S[x].push_back(y);
	}
	REP(i, 1000000){
		REP(j, S[i].size()){
			bool flag;
			int diff_x, diff_y;
			diff_x = i-tx[0];
			diff_y = S[i][j]-ty[0];
			FOR(k, 1, m){
				flag = false;
				REP(l, S[tx[k]+diff_x].size()){
					if(S[tx[k]+diff_x][l] == ty[k]+diff_y){
						flag = true;
					}
				}
				if(!flag){
					break;
				}
			}
			if(flag){
				cout << diff_x << " " << diff_y << endl;
				j = S[i].size();
				i = 1000000;
			}
		}
	}
	}

}

星座探し

問題

あなたは星空の写真の中から星座を探している．写真には必ず，探したい星座と同じ形・向き・大きさの図形がちょうど一つ含まれている．ただし，写真の中には星座を構成する星以外に余分な星が写っている可能性がある．

例えば，図 1 の星座は図 2 の写真に含まれている（丸で囲んで示した）．与えられた星座の星の座標を x 方向に 2， y 方向に −3 だけ平行移動すると写真の中の位置になる．

探したい星座の形と写真に写っている星の位置が与えられたとき，星座の座標を写真の中の座標に変換するために平行移動するべき量を答えるプログラムを書け．

図 1: 探したい星座

図 2: 星空の写真

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

入力の 1 行目には探したい星座を構成する星の個数 m が書かれている．続く m 行には探したい星座を構成する m 個の星の x 座標と y 座標を示す整数が空白区切りで書かれている． m+2 行目には写真に写っている星の個数 n が書かれている．続く n 行には写真に写っている n 個の星の x 座標と y 座標を示す整数が空白区切りで書かれている．

星座を構成する m 個の星の位置はすべて異なる．また，写真に写っている n 個の星の位置はすべて異なる． 1 ≤ m ≤ 200， 1 ≤ n ≤ 1000 である．星の x 座標と y 座標はすべて 0 以上 1000000 以下である．

m が 0　のとき入力の終わりを示す. データセットの数は 5 を超えない．

出力

各データセットの出力は 1 行からなり， 2 個の整数を空白区切りで書く．これらは探したい星座の座標をどれだけ平行移動すれば写真の中の座標になるかを表す．最初の整数が x 方向に平行移動する量，次の整数が y 方向に平行移動する量である．

入出力例

入力例

5
8 5
6 4
4 3
7 10
0 10
10
10 5
2 7
9 7
8 10
10 2
1 2
8 1
6 7
6 0
0 9
5
904207 809784
845370 244806
499091 59863
638406 182509
435076 362268
10
757559 866424
114810 239537
519926 989458
461089 424480
674361 448440
81851 150384
459107 795405
299682 6700
254125 362183
50795 541942
0

出力例

2 -3
-384281 179674

入出力例の１つ目は上の図に対応している．

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。


//JOI 0528 Common Sub-String
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
	string s, t;
	for(int o=0;o<4;o++){
                cin>>s>>t;
		int roop1=0, save=0, ans = 0;
	for (int i = 0; i<s.size(); i++){
		for (int j = 0; j<t.size(); j++){
			if (s[i] == t[j]){
				roop1 = 0;
				save= 0;
				while (1){
						if (s[i + roop1] == t[j + roop1]){
							save += 1;
							roop1++;
						}
					else if (s[i + roop1] != t[j + roop1]){
							ans=max(ans,save);
							break;
					}
				}
			}
		}
	}
	cout<<ans<<endl;
	}
	return 0;
}

共通部分文字列

問題

2 個の文字列が与えられたとき, 両方の文字列に含まれる文字列のうち最も長いものを探し, その長さを答えるプログラムを作成せよ.

ここで, 文字列 s が文字列 t に含まれるとは, t の中に s が連続して現れることをいう. 空文字列, すなわち長さ 0 の文字列は, どんな文字列にも含まれる. 例えば, 文字列 ABRACADABRA には次の文字列が含まれる: ABRA, RAC, D, ACADABRA, ABRACADABRA,空文字列など. 一方, 文字列 ABRACADABRA には次の文字列は含まれない: ABRC, RAA,BA, K など.

例

例 1: 文字列として ABRACADABRA と ECADADABRBCRDARA が与えられた場合, 両方に含まれる文字列には CA や CADA や ADABR や空文字列などがある. そのうち最も長いのは ADABR であり, その長さは 5 である. 2 個の文字列の中に含まれる ADABR
の位置を以下に示す.

ABRACADABRA

ECADADABRBCRDARA

例 2: 文字列として UPWJCIRUCAXIIRGL と SBQNYBSBZDFNEV が与えられた場合, 両方に含まれる文字列は空文字列のみであり, その長さは 0 である.

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

入力は 2 行からなり, 1 行目に 1 個目の文字列が, 2 行目に 2 個目の文字列が与えられる. 文字列は英大文字からなり, 各々の文字列の長さは 1 以上 4000 以下である.

採点用データのうち, 配点の 30% 分については, 各々の文字列の長さは 1 以上 50以下である.

入力の終わりは EOF で示される. データセットの数は 10 を超えない．

出力

データセットごとに与えられた 2 個の文字列の両方に含まれる文字列のうち最も長いものの長さを 1 行に出力する.

入出力例

入力例

ABRACADABRA
ECADADABRBCRDARA
UPWJCIRUCAXIIRGL
SBQNYBSBZDFNEV

出力例

5
0

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。


#include "stdio.h"
#include "stdlib.h"

int s[1000];

typedef struct
{
	int a;
	int b;
	int w1;
	int w2;
}yoko;

yoko w[100000];

int z[1000];

int ten[1000];

int sortw(const void* a,const void* b)
{
	if(((yoko*)a)[0].a < ((yoko*)b)[0].a)
	{
		return -1;
	}
	else if(((yoko*)a)[0].a == ((yoko*)b)[0].a)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}

int ans[1000];

int main()
{
	int nww = 0;
	while(1)
	{
		int n,m,h,k;
		scanf("%d %d %d %d",&n,&m,&h,&k);
		if(n == 0 && m == 0 && h == 0 && k == 0)
		{
			break;
		}
		for(int i = 0; i < n; i++)
		{
			scanf("%d",&(s[i]));
		}
		for(int i = 0; i < m; i++)
		{
			scanf("%d %d",&(w[i].b),&(w[i].a));
		}
		qsort(w,m,sizeof(yoko),sortw);
		for(int i = 0; i < n; i++)
		{
			z[i] = i;
		}
		int d;
		for(int i = 0; i < m; i++)
		{
			w[i].w1 = z[w[i].b];
			w[i].w2 = z[w[i].b - 1];
			d = z[w[i].b];
			z[w[i].b] = z[w[i].b - 1];
			z[w[i].b - 1] = d;
		}
		for(int i = 0; i < n; i++)
		{
			ten[z[i]] = s[i];
		}
		int min;
		int www = 0;
		for(int i = 0; i < k; i++)
		{
			www = www + ten[i];
		}
		min = www;
		for(int i = 0; i < m; i++)
		{
			d = ten[w[i].w1];
			ten[w[i].w1] = ten[w[i].w2];
			ten[w[i].w2] = d;
			www = 0;
			for(int i = 0; i < k; i++)
			{
				www = www + ten[i];
			}
			if(www < min)
			{
				min = www;
			}
			d = ten[w[i].w1];
			ten[w[i].w1] = ten[w[i].w2];
			ten[w[i].w2] = d;
		}
		ans[nww] = min;
		nww++;
	}
	for(int i = 0; i < nww; i++)
	{
		printf("%d\n",ans[i]);
	}
	return 0;
}

あみだくじ

問題

あなたは J 君と一緒にあみだくじを使って遊んでいる.あみだくじは n 本の縦棒と
m 本の横棒からなる.縦棒には左から順に 1 から n の番号がついており,縦棒 i の下端には正整数 si が書かれている.

図 3-1 あみだくじの例(n = 4, m = 5, s1 = 20, s2 = 80, s3 = 100, s4 = 50)

縦棒 i の一番上から順に道をたどっていき到達した下端に書かれている整数が, 縦
棒 i を選んだ場合の得点である.例えば,図 3-1 では,縦棒 1 を選ぶと得点は 80 点
であり,縦棒 2 を選ぶと得点は 100 点である.

図 3-2 道のたどり方の例

J 君は縦棒 1 から縦棒 k までの連続した k 本を選ぶことにした.それら k 本の縦棒を選んだときの点数の合計が J 君の得点となる.ただし,あなたはあみだくじ内の
横棒を一本選び,その横棒をあみだくじから削除することができる. (削除しなくてもよい.) もし,あなたが横棒を一本削除した場合は,削除後のあみだくじにおいて,
縦棒 1 から縦棒 k までの連続した k 本の縦棒を選んだときの点数の合計が J 君の得点となる.

入力としてあみだくじの形と J 君の選ぶ縦棒の本数 k が与えられたとき,J 君の得
点の最小値を求めるプログラムを作成せよ.

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

1 行目には 4 つの整数 n, m, h, k が空白区切りで書かれている. n (2 ≤ n ≤ 1000) は縦棒の本数を, m (1 ≤ m ≤ 100000) は横棒の本数を, h (2 ≤ h ≤ 1000) は縦棒の長さを,k (1 ≤ k ≤ n) は J 君が選ぶ縦棒の本数を表す.

続く n 行には縦棒の下端に書かれている点数が書かれている. i + 1 行目 (1 ≤ i ≤ n)には正整数 si が書かれている. また, s1 + s2 + ... + sn ≤ 2000000000 = 2 × 109 を満たす.

続く m 行には横棒の位置が書かれている.横棒には 1 から m までの番号がついている.i + n + 1 行目 (1 ≤ i ≤ m) には, 横棒 i の位置を表す 2 つの整数 ai, bi (1 ≤ ai ≤ n - 1, 1 ≤ bi ≤ h - 1) が空白区切りで書かれており,横棒 i が縦棒 ai と縦棒 ai + 1 を結び, 横棒 i の上端からの距離が bi であることを表す. ただし,どの 2 つの横棒も端点を共有することはない.

採点用データのうち,配点の 20 % 分は横棒を削除しない場合に J 君の得点が最少となる.また,配点の 30 % 分は n ≤ 20, m ≤ 30, h ≤ 10 を満たし,配点の 60 % 分は m ≤ 1000 を満たす.

入力の終わりは 4つのゼロを含む行で示される. データセットの数は 10 を超えない．

出力

データセットごとに, J 君の得点の最小値を1 行に出力する.

入出力例

入力例

4 5 7 2
20
80
100
50
1 1
2 6
2 3
1 5
3 1
2 2 5 1
10
20
1 1
1 3
0 0 0 0

出力例

100
10

1つ目の例 は図 3-1 に対応し,あなたが横棒 4 (縦棒 1 と縦棒 2 を上端から距離 5 の場所で結ぶ横棒)を削除したとき,J 君の得点は最小になる.例 2 では,あなたが横棒を削除しない場合に J 君の得点が最小になる. (図3-3 を見よ.)

図 3-3

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。


お菓子の分割

問題

長さ N ミリメートルの棒状のお菓子が 1 本ある(ここで N は偶数). 2 人の JOI
関係者が,このお菓子を複数本に切断して,合計 N/2 ミリメートルずつに分けること
にした.

理由は不明であるが,このお菓子は場所によって切断のしやすさが異なっている.
2 人は,お菓子を左から 1 ミリメートルごとに調べ,各場所で切断に何秒かかるか
を割り出した.2 人がお菓子を分けるための切断にかかる秒数の最小値を求めるプ
ログラムを作成せよ.

入力

入力の 1 行目には,棒の長さ N(2 ≤ N ≤ 10000 ,ただし N は偶数) が書かれてい
る.入力の i + 1 行目 (1 ≤ i ≤ N − 1) には,左端から i ミリメートル目の場所の切
断にかかる秒数を表す整数 ti (1 ≤ ti ≤ 10000) が書かれている.切断可能な場所が
N − 1 箇所であることに注意せよ.

採点用データのうち,配点の 5% 分については,高々 2 カ所を切断することで最
小値を実現でき,10% 分については,高々 3 カ所を切断することで最小値を実現で
きる.配点の 20% 分については,N ≤ 20 である.

出力

出力は2 人がお菓子を分るための切断にかかる秒数の最小値を含む 1 行からなる.

入出力例

入力例 1

6
1
8
12
6
2

出力例 1

7

この場合,左端から 1 ミリメートルと 4 ミリメートルの場所で切断するとかかる
秒数が最小となる.かかる秒数は 1 秒と 6 秒で,合計 7 秒である.

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。


指輪 (Ring)

問題

あなたは N 個の指輪を持っている．どの指輪にも，アルファベットの大文字 10 文字からなる文字列が刻印されている．指輪には文字列の最初と最後がつながった形で文字が刻印されている．指輪に刻印された文字列を逆順に読む心配はない．

探したい文字列が与えられたとき，その文字列を含む指輪が何個あるかを求めるプログラムを作成せよ．

入力

入力は 2+N 行からなる．

1 行目には，1 文字以上 10 文字以下のアルファベットの大文字からなる探したい文字列が書かれている．

2 行目には，指輪の個数 N ( 1 ≦ N ≦ 100 )が書かれている．

2+i 行目(1 ≤ i ≤ N )には， i 個目の指輪に刻印されている 10 文字からなる文字列が書かれている．

出力

探したい文字列を含む指輪の個数を表す整数を 1 行で出力せよ．

入出力例

入力例 1

ABCD
3
ABCDXXXXXX
YYYYABCDXX
DCBAZZZZZZ

出力例 1

2

入力例 2

XYZ
1
ZAAAAAAAXY

出力例 2

1

入力例 2 の指輪には「XYZ」という文字列が 1 つ含まれている．これは、指輪の文字列の最初と最後がつながっているためである．

入力例 3

PQR
3
PQRAAAAPQR
BBPQRBBBBB
CCCCCCCCCC

出力例 3

2

入力例 3 の 1 個目の指輪には「PQR」という文字列が 2 つ含まれており， 2 個目の指輪には「PQR」という文字列が 1 個含まれており， 3 個目の指輪には「PQR」という文字列が含まれていない．そのため「PQR」という文字列が含まれている指輪の数は 2 個となる．

問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。


#include<bits/stdc++.h>
using namespace std;

inline string toString(int a){
  stringstream ss;
  ss << a;
  return ss.str();
}

inline int toInt(string s){
  stringstream ss(s);
  int res;
  ss >> res;
  return res;
}

inline bool is_prime(int a){
  if(a<=1)return false;
  for(int i=2;i*i<=a;i++){
    if(a%i==0)return false;
  }
  return true;
}

int rec(int d, int n, string s, string c){
  if(n>4)return -1;
  if(d==n){
    string pal = s + c;
    reverse(s.begin(),s.end());
    pal += s;
    int p = toInt(pal);
    return is_prime(p)?p:-1;
  }

  int res = -1;
  for(int i=0;i<10;i++){
    if(d==0 && (i%2==0 || i%5==0))continue;
    res = max( res, rec(d+1, n, s + toString(i), c) );
  }
  return res;
}

int main(){
  int n,c;
  cin >> n >> c;
  string center = (c<0)?"":toString(c);
  int res = rec(0,n,"",center);

  if(res<0){
    for(int i=0;i<n;i++)cout << "9";
    cout << center;
    for(int i=0;i<n;i++)cout << "9";
    cout << endl;
  }else{
    cout << res << endl;
  }
}

問題５

　Ｊ中学校の運動会で次のようなクラス対抗の競技を行なうことになった．
各クラスから生徒代表の男女 n ペア

     　　 (男子生徒 b1， 女子生徒 g1)， (男子生徒 b2， 女子生徒 g2)， … ， (男子生徒 bn， 女子生徒 gn)

を選び，
0 から 9 までの数字が書かれた旗を自由に選んでもらい
（それぞれの旗は十分な個数ある），
横一列に並んでもらう．
ただし，
ペアになっている男子生徒と女子生徒は同じ番号の旗を一人１つずつ
選ばなければならず，
並び順は

     　　 b1 b2 … bn c gn … g2 g1

のように，
男子生徒達 n 人の並び順
b1 b2 … bn とは逆の順番
gn … g2 g1 で女子生徒達は
並ばなければならない．
中央の c には，
クラス担任の先生があらかじめ審判長によって指定された
番号の付いた旗を持って立つ場合と，
立たないことを審判長に指定される場合とがある．

　こうして並んだ生徒達（と先生）が持った旗の番号
を 2n 桁（または 2n+1 桁）の整数と考えたとき，
それが素数である方が勝ちである．
ただし，
両クラスとも素数だった場合あるいは両クラスとも素数でなかった場合には，
数が大きい方が勝ちである． また，

      0 b2 … bn c gn … g2 0
　あるいは
0 b2 … bn gn … g2 0

のように先頭に 0 が来るものは，
普通使われる数の表し方ではないので禁止されている．

　Ｊ中学校の生徒であるあなたは，
自分のクラスが勝つためにはどのように並ぶのがよいかを
考えなければならない．

　入力ファイルの１行目に正整数 n と
１桁の整数 c（先生が持つ旗の番号）が
１つの半角空白文字で区切られて書かれている．
c<0 のときは，
先生が中央に立たないことを表わす．

与えられる入力は 1≦n≦10 である．

　負けない並び方の順番

     b1 b2 … bn c gn … g2 g1
　または
b1 b2 … bn gn … g2 g1

を出力せよ．

出力ファイルにおいては，
出力の最後にも改行コードを入れること．

入出力例

入力例１

1 0

出力例１

101

入力例２

1 5

出力例２

757

入力例３

3 7

出力例３

9957599

入力例４

1 -1

出力例４

11

問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。


#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <complex>
#include <queue>
#include <map>
#include <set>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;

#define REP(i,n) for(int i=0;i<(int)n;++i)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define ALL(c) (c).begin(), (c).end()
const int INF = 1<<29;

int main() {
  int n, U;
  while(cin>>n>>U, n||U) {
    int bitmask[n];
    int c[n];
    memset(bitmask,0,sizeof(bitmask));
    REP(i,n) {
      int k;
      cin >> c[i] >> k;
      REP(j,k) {
        int r;
        cin >> r;
        bitmask[i] |= 1<<r;
      }
    }
    if (U==0) {                 // ツつ「ツづゥツつゥツ不ツ鳴セ
      cout << 0 << endl;
      continue;
    }
    bool ok = 0;
    int res = 0;
    for (int k=1; k<=n; ++k) {
      int S = (1<<k)-1;
      while(S<1<<n) {
        int sum = 0;
        bool dame = 0;
        REP(i,k) {
          if (S>>i&1) {
            if (S&bitmask[i] != bitmask[i]) {
              dame = 1;
              break;
            }
            sum += c[i];
          }
        }
        if (!dame && sum >= U) {
          ok = 1;
          res = k;
          break;
        }
        int x = S&-S, y=S+x;
        S = ((S & ~y) / x >> 1) | y;
      }
      if (ok) break;
    }
    cout << res << endl;
  }
}

Problem D: Course Planning for Lazy Students

会津大学では2009年度より、授業履修に関する新しい制度を開始した。新制度では必修科目を撤廃し、それぞれの進路を考慮して科目を自由に選択できるようになった。

しかし、どの科目も無条件で履修できるわけではなく、特定の科目を履修するためには、先修条件を満たしている必要がある。下図に履修計画表の一部の例を示す：

図の長方形が１つの科目を表し科目名と単位数を含んでいる。図の矢印が先修条件を表す。矢印の意味は、矢印の終点で指されている科目を履修するためには、その矢印の始点を示す科目を修得している必要がある。例えば、Linear Algebra II (線形代数２)を履修するためには、Linear Algebra I (線形代数１)を修得している必要がある。また、Applied Algebra (応用代数)を履修するためには、Linear Algebra I と Discrete Systems (離散系論)の両方を修得している必要がある。

さて、履修登録計画において卒業に要する最低限の合計単位数 U を満たす履修科目の組み合わせは、怠慢な学生にとって興味深いものである。

あなたの仕事は、与えられた履修計画表と U を読み込み、最低限の履修科目数を報告するプログラムを作成することである。これは計画であるため、履修登録した科目は必ず単位を修得できるものと仮定する。

Input

入力は複数のデータセットからなる。各データセットは以下の形式で与えられる：

n U

c0 k0 r01 r02 ... r0k0

c1 k1 r11 r12 ... r1k1

.

.

cn-1 kn-1 r(n-1)1 r(n-1)2 ... r(n-1)kn-1

n (1 ≤ n ≤ 20) は履修計画表が含む科目の数を示す整数である。科目には 0 から n-1 までの番号が割り当てられているものとし、以下 i 番目の科目を科目 i と呼ぶことにする。

U (1 ≤ U ≤ 100) は必要な合計単位数を表す整数である。

ci (1 ≤ ci ≤ 10)は科目 i の単位数を示す。次の ki (0 ≤ ki ≤ 5) は科目 i の先修科目の数を示す。それに続く ri1 ri2 ... riki は科目 i の先修科目の科目番号を示す。

ある科目から先修条件を表す矢印を１つ以上たどり、再びその科目に戻るような入力は与えられない。また、U を満たす科目の組み合わせが必ず存在すると仮定してよい。

n と U がともに 0 のとき入力の終わりを示す。データセットの数は 100 を超えない。

Output

各データセットについて、最低限必要な科目数を１行に出力せよ。

Sample Input

4 4
1 0
3 2 0 2
2 0
2 0
3 6
1 0
3 2 0 2
2 0
0 0

Output for the Sample Input

2
3


#include<bits/stdc++.h>
using namespace std;
typedef vector<int>vi;
typedef vector<vi>vvi;

const int B=80;
int H,W,Q;
vi *fld,*bucket;

bool solve(){
    scanf("%d%d%d",&H,&W,&Q);
    if(H==0&&W==0&&Q==0)return false;
    fld=new vi[H];
    bucket=new vi[H/B+1];
    fill_n(fld,H,vi(W));
    fill_n(bucket,H/B+1,vi(W/B+1,INT_MAX));
    vi latte(H/B+1,INT_MAX);
    vi malta(W/B+1,INT_MAX);
    for(int i=0;i<H;++i){
        for(int j=0;j<W;++j){
            int a;
            scanf("%d",&a);
            fld[i][j]=a;
            bucket[i/B][j/B]=min(bucket[i/B][j/B],a);
            latte[i/B]=min(latte[i/B],a);
            malta[j/B]=min(malta[j/B],a);
        }
    }

    while(Q--){
        int x1,y1,x2,y2;
        scanf("%d%d%d%d",&y1,&x1,&y2,&x2);
        ++y2;++x2;

        int mi=INT_MAX;
        if(mi<latte[y1/B])y1=(y1/B+1)*B;
        while(y1<y2&&y1%B!=0){
            for(int j=x1;j<x2;++j){
                if(mi<bucket[y1/B][j/B]){
                    j=(j/B+1)*B-1;
                    continue;
                }
                mi=min(mi,fld[y1][j]);
            }
            ++y1;
        }
        //if(mi<latte[y2/B]&&y2%B!=0)y2=(y2/B-1)*B;
        while(y1<y2&&y2%B!=0){
            --y2;
            for(int j=x1;j<x2;++j){
                if(mi<bucket[y2/B][j/B]){
                    j=(j/B+1)*B-1;
                    continue;
                }
                mi=min(mi,fld[y2][j]);
            }
        }
        if(mi<malta[x1/B])x1=(x1/B+1)*B;
        while(x1<x2&&x1%B!=0){
            for(int i=y1;i<y2;++i){
                if(mi<bucket[i/B][x1/B]){
                    i=(i/B+1)*B-1;
                    continue;
                }
                mi=min(mi,fld[i][x1]);
            }
            ++x1;
        }
        //if(mi<malta[x2/B]&&x2%B!=0)x2=(x2/B-1)*B;
        while(x1<x2&&x2%B!=0){
            --x2;
            for(int i=y1;i<y2;++i){
                if(mi<bucket[i/B][x2/B]){
                    i=(i/B+1)*B-1;
                    continue;
                }
                mi=min(mi,fld[i][x2]);
            }
        }
        int bx1=x1/B,bx2=x2/B;

        while(y1<y2){
            int by1=y1/B;
            if(latte[by1]<mi){
                for(int j=bx1;j<bx2;++j)
                    mi=min(mi,bucket[by1][j]);
            }
            y1+=B;
        }

        printf("%d\n",mi);
    }
    return true;
}
int main(){
    while(solve());
}

Problem G: School of Killifish

Jon is the leader of killifish.
Jon have a problem in these days.
Jon has a plan to built new town in a pond.
Of course new towns should have a school for children. But there are some natural enemies in a pond.
Jon thinks that the place of a school should be the safest place in a pond for children.

Jon has asked by some construction companies to make construction plans and Jon has q construction plans now.
The plan is selected by voting. But for each plan, the safest place for the school should be decided before voting.

A pond is expressed by a 2D grid whose size is r*c.
The grid has r rows and c columns. The coordinate of the top-left cell is (0,0). The coordinate of the bottom-right cell is expressed as (r-1,c-1).
Each cell has an integer which implies a dangerousness.
The lower value implies safer than the higher value.
q plans are given by four integer r1 ,c1 ,r2 and c2 which represent the subgrid.
The top-left corner is (r1,c1) and the bottom-right corner is (r2,c2).

You have the r*c grid and q plans. Your task is to find the safest point for each plan.
You should find the lowest value in the subgrid.

Input

Input consists of multiple datasets.

Each dataset is given in the following format.

r c q
grid0,0 grid0,1 ... grid0,c-1
...
gridr-1,0 ... gridr-1,c-1
r1 c1 r2 c2
...
r1 c1 r2 c2

The first line consists of 3 integers, r ,c , and q .
Next r lines have c integers.
gridi,j means a dangerousness of the grid.
And you can assume 0 ≤ gridi,j ≤ 231-1.
After that, q queries, r1, c1, r2 and c2, are given.

The dataset satisfies following constraints.

r*c ≤ 106

q ≤ 104

For each query, you can assume that r1≤ r2 and c1 ≤ c2 .

If r * c ≤ 250000, q ≤ 100 is assured.
If r * c > 250000, Input consists of only that case.

Output

For each query you should print the lowest value in the subgrid in a line.

Sample input

3 3 4
1 2 3
4 2 2
2 1 1
0 0 2 2
0 0 1 1
1 0 1 0
0 1 1 2
1 10 4
1 2 3 4 5 6 7 8 9 10
0 0 0 9
0 0 0 4
0 5 0 9
0 4 0 5
0 0 0

Sample output

1
1
4
2
1
1
6
5


#include <iostream>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <cassert>
using namespace std;
int dicea[6],diceb[6];
string str[21];
int mk_num(string *);

void lr_hanten(string a[]){
  for(int i=0;i<7;i++)
    for(int j=0;j<7/2;j++) swap(a[i][j],a[i][6-j]);
}

void ud_hanten(string a[]){
  for(int i=0;i<7;i++)
    for(int j=0;j<7/2;j++) swap(a[j][i],a[6-j][i]);
}

void rol_90(string a[]){
  string b[7];
  for(int i=0;i<7;i++)
    for(int j=0;j<7;j++) {
      b[i] += a[j][6-i];
      if(b[i][j] == '-') b[i][j] = '|';
      else if(b[i][j] =='|') b[i][j] = '-';
    }
  for(int i=0;i<7;i++) a[i] = b[i];
}

void choice(string num[],int x,int y){
  for(int i=0;i<7;i++){
    num[i]="";
    for(int j=0;j<7;j++) num[i]+=str[y+i][x+j];
  }
}

void mk_dice(){
  string num[2][7];
  //ue
  choice(num[0],7,0),choice(num[1],36,0);
  lr_hanten(num[0]),lr_hanten(num[1]);
  dicea[0] = mk_num(num[0]),diceb[0]=mk_num(num[1]);

  //hidari
  choice(num[0],0,7),choice(num[1],29,7);
  lr_hanten(num[0]),lr_hanten(num[1]);
  rol_90(num[0]),rol_90(num[1]);
  dicea[1] = mk_num(num[0]),diceb[1] = mk_num(num[1]);

  //mid_hidari
  choice(num[0],7,7),choice(num[1],36,7);
  lr_hanten(num[0]),lr_hanten(num[1]);
  dicea[2] = mk_num(num[0]),diceb[2] = mk_num(num[1]);

  //mid_migi
  choice(num[0],14,7),choice(num[1],43,7);
  lr_hanten(num[0]),lr_hanten(num[1]);
  for(int i=0;i<3;i++)rol_90(num[0]),rol_90(num[1]);
  dicea[3] = mk_num(num[0]),diceb[3] = mk_num(num[1]);

  //migi
  choice(num[0],21,7),choice(num[1],50,7);
  lr_hanten(num[0]),lr_hanten(num[1]);
  dicea[4] = mk_num(num[0]),diceb[4] = mk_num(num[1]);

  //sita
  choice(num[0],7,14),choice(num[1],36,14);
  ud_hanten(num[0]),ud_hanten(num[1]);
  lr_hanten(num[0]),lr_hanten(num[1]);
  dicea[5] = mk_num(num[0]),diceb[5] = mk_num(num[1]);
}

int main(){
  srand((unsigned)time(NULL));
  while(1) {
    for(int i=0;i<21;i++){
      cin >> str[i];
      if(str[i]=="0")break;
    }
    if(str[0]=="0")break;
    mk_dice();
    int a=0,b=0;
    for(int i=0;i<6;i++) assert(dicea[i]!=-1 && diceb[i]!=-1);

    int arr[6]={};
    for(int i=0;i<100000;i++){
      arr[rand()%6]++;
      if(dicea[rand()%6] > diceb[rand()%6]) a++;
      else if(dicea[rand()%6]<diceb[rand()%6])b++;
    }
    // for(int i=0;i<6;i++) cout <<arr[i]<<" ";cout<<endl;
    if(a>b-500) cout<<"HIGH"<<endl;
    else cout <<"LOW"<<endl;
  }

}

int mk_num(string a[]){
  if(a[1]=="#.....#" &&
     a[2]=="#...|.#") return 1;

  if(a[1]=="#..-..#" &&
     a[2]=="#...|.#" &&
     a[3]=="#..-..#" &&
     a[4]=="#.|...#" &&
     a[5]=="#..-..#") return 2;

  if(a[1]=="#..-..#" &&
     a[2]=="#...|.#" &&
     a[3]=="#..-..#" &&
     a[4]=="#...|.#" &&
     a[5]=="#..-..#") return 3;

  if(a[1]=="#.....#" &&
     a[5]=="#.....#") return 4;

  if(a[1]=="#..-..#" &&
     a[2]=="#.|...#" &&
     a[3]=="#..-..#" &&
     a[4]=="#...|.#" &&
     a[5]=="#..-..#") return 5;

  if(a[1]=="#..-..#" &&
     a[2]=="#.|...#" &&
     a[3]=="#..-..#" &&
     a[4]=="#.|.|.#" &&
     a[5]=="#..-..#") return 6;

  if(a[3]=="#.....#" &&
     a[5]=="#.....#") return 7;

  if(a[1]=="#..-..#" &&
     a[2]=="#.|.|.#" &&
     a[3]=="#..-..#" &&
     a[4]=="#.|.|.#" &&
     a[5]=="#..-..#") return 8;

  if(a[1]=="#..-..#" &&
     a[2]=="#.|.|.#" &&
     a[3]=="#..-..#" &&
     a[4]=="#...|.#" &&
     a[5]=="#..-..#") return 9;
  return -1;
}

Problem B: High & Low Cube

僕は近所の小学生たちと一緒に夏祭りに来ていた。有り体に言えば保護者役だが、出店の焼きそばやたこ焼きなんかが焼ける匂い、時折聞こえる打ち上げ花火の音などは、この歳になっても心が踊るものがある。が、好奇心旺盛な子供たちがはぐれないように、今日はしっかり見守っていないと。

子供たちはとある出店に興味を持ったようだった。覗き込んでみると、そこでは出店のおじさんとサイコロを使ったゲームをして、勝てば景品が貰えることになっていた。そのゲームは、 High & Low と呼ばれる単純なものだ。参加者とおじさんは1個ずつサイコロを振るが、その前に参加者は、自分の出目がおじさんの出目より大きいか小さいかを予想する。予想が当たれば勝利であり、同じ目が出た場合はどちらもサイコロを振り直す。

このゲームの少し厄介なところは、参加者のサイコロとおじさんのサイコロが違うものであるかもしれない、という点だ。参加者はあらかじめ両者のサイコロの展開図を見ることができるので、それをヒントに予想することになる。

つまり、簡単な確率の計算だ。とはいえ確率は高校数学の範囲で、小学生にはちょっと荷が重いかもしれない。子供たちの中で一番利発そうな子でさえ、三つ編みにした髪を揺らしながら考え込んでいる。もうすぐ僕に助けを求めてくることだろう。さて、たまにはオトナらしいところを見せてあげようではないか。

Input

入力は複数のケースからなる。

各ケースでは、サイコロの展開図が21×57のグリッドで与えられる。

最初の21×28（(0,0)が左上,(20,27)が右下）のグリッドが参加者のサイコロを表す。

最後の21×28（(0,29)が左上,(20,56)が右下）がおじさんのサイコロを表す。

参加者のサイコロの各面は(0,7)、(7,0)、(7,7)、(7,14)、(7,21)、(14,7)を左上とする7×7のサブグリッドで与えられている。

展開図に書かれている数字は、それぞれ元の数字を

左右反転

左右反転、そのあとで反時計回りに90度回転

左右反転

左右反転、そのあとで反時計回りに270度回転

左右反転

上下反転、そのあとで左右反転

させたものである。

おじさんのサイコロの各面は(0,36)、(7,29)、(7,36)、(7,43)、(7,50)、(14,36)を左上とする７×７のサブグリッドで与えられている。

おじさんのサイコロの展開図に書かれている数字は参加者のサイコロと同じ規則で描かれている。

サイコロの各面には1から9までの中のどれかが書かれている。
数字は以下のような7x7のグリッドで与えられる。
#######
#.....#
#...|.#
#.....#
#...|.#
#..-..#
#######

#######
#..-..#
#...|.#
#..-..#
#.|...#
#..-..#
#######

#######
#..-..#
#...|.#
#..-..#
#...|.#
#..-..#
#######

#######
#.....#
#.|.|.#
#..-..#
#...|.#
#.....#
#######

#######
#..-..#
#.|...#
#..-..#
#...|.#
#..-..#
#######

#######
#..-..#
#.|...#
#..-..#
#.|.|.#
#..-..#
#######

#######
#..-..#
#...|.#
#.....#
#...|.#
#.....#
#######

#######
#..-..#
#.|.|.#
#..-..#
#.|.|.#
#..-..#
#######

#######
#..-..#
#.|.|.#
#..-..#
#...|.#
#..-..#
#######

ただし上記の数字を90度、または270度回転させた時、"|"と"-"は入れ替わっている。

入力の終わりは1つの0からなる行によって与えられる

入力として与えられるサイコロは必ず正しい物である。
また決着がつかないようなサイコロは与えられない。

Output

"HIGH"になる場合と"LOW"になる場合で確率が高いほうを1行に出力せよ。
両者の確率が同じ場合は"HIGH"を出力せよ。

Sample input

.......#######......................#######..............
.......#.....#......................#..-..#..............
.......#.|...#......................#.|.|.#..............
.......#.....#......................#..-..#..............
.......#.|...#......................#.|...#..............
.......#..-..#......................#..-..#..............
.......#######......................#######..............
############################.############################
#.....##..-..##.....##..-..#.#.....##..-..##.....##..-..#
#.-.-.##...|.##.-.-.##.|.|.#.#.....##.|.|.##.-.-.##.|.|.#
#|.|.|##..-..##|.|.|##..-..#.#....|##..-..##|.|.|##..-..#
#...-.##.|...##...-.##.|.|.#.#.-.-.##.|...##...-.##.|...#
#.....##..-..##.....##..-..#.#.....##..-..##.....##..-..#
############################.############################
.......#######......................#######..............
.......#..-..#......................#..-..#..............
.......#.|...#......................#.|...#..............
.......#..-..#......................#..-..#..............
.......#.|.|.#......................#...|.#..............
.......#..-..#......................#..-..#..............
.......#######......................#######..............
.......#######......................#######..............
.......#..-..#......................#..-..#..............
.......#.|...#......................#...|.#..............
.......#..-..#......................#..-..#..............
.......#...|.#......................#.|.|.#..............
.......#..-..#......................#..-..#..............
.......#######......................#######..............
############################.############################
#.....##..-..##.....##..-..#.#.....##..-..##.....##..-..#
#.-.-.##...|.##.-.-.##.|.|.#.#...-.##...|.##.-...##.|.|.#
#|.|.|##..-..##|.|.|##..-..#.#|.|.|##..-..##|.|.|##..-..#
#.-.-.##.|...##...-.##.|...#.#.-...##.|.|.##.-.-.##.|...#
#.....##..-..##.....##..-..#.#.....##..-..##.....##..-..#
############################.############################
.......#######......................#######..............
.......#..-..#......................#..-..#..............
.......#...|.#......................#.|...#..............
.......#..-..#......................#..-..#..............
.......#.|...#......................#...|.#..............
.......#..-..#......................#..-..#..............
.......#######......................#######..............
.......#######......................#######..............
.......#..-..#......................#..-..#..............
.......#.|...#......................#.|.|.#..............
.......#..-..#......................#..-..#..............
.......#...|.#......................#.|...#..............
.......#..-..#......................#..-..#..............
.......#######......................#######..............
############################.############################
#.....##..-..##.....##..-..#.#.....##..-..##.....##.....#
#.-.-.##.|.|.##.-.-.##...|.#.#.....##.|.|.##...-.##.|...#
#|.|.|##..-..##|....##..-..#.#....|##..-..##|.|.|##.....#
#.-.-.##.|.|.##.....##.|.|.#.#.-.-.##.|.|.##.-...##.|...#
#.....##..-..##.....##..-..#.#.....##..-..##.....##..-..#
############################.############################
.......#######......................#######..............
.......#..-..#......................#..-..#..............
.......#.|.|.#......................#.|...#..............
.......#..-..#......................#..-..#..............
.......#...|.#......................#...|.#..............
.......#..-..#......................#..-..#..............
.......#######......................#######..............
.......#######......................#######..............
.......#..-..#......................#..-..#..............
.......#.|...#......................#.|.|.#..............
.......#..-..#......................#..-..#..............
.......#...|.#......................#.|...#..............
.......#..-..#......................#..-..#..............
.......#######......................#######..............
############################.############################
#.....##..-..##.....##..-..#.#.....##..-..##.....##..-..#
#.-.-.##...|.##.-.-.##.|.|.#.#.-...##.|.|.##.-...##.|.|.#
#|.|.|##..-..##|.|.|##..-..#.#|.|.|##..-..##|.|.|##..-..#
#...-.##.|...##.-.-.##.|.|.#.#.-.-.##.|...##.-.-.##.|.|.#
#.....##..-..##.....##..-..#.#.....##..-..##.....##..-..#
############################.############################
.......#######......................#######..............
.......#..-..#......................#..-..#..............
.......#...|.#......................#.|.|.#..............
.......#..-..#......................#..-..#..............
.......#.|...#......................#...|.#..............
.......#..-..#......................#..-..#..............
.......#######......................#######..............
0

Sample output

LOW
HIGH
HIGH
LOW

The University of Aizu Programming Contest 2011 Summer

原案、問題文: Takashi Tayama


#include <bits/stdc++.h>
using namespace std;

#define rep(i,x,y) for(int i=(x);i<(y);++i)
#define debug(x) #x << "=" << (x)

#ifdef DEBUG
#define _GLIBCXX_DEBUG
#define dump(x) std::cerr << debug(x) << " (L:" << __LINE__ << ")" << std::endl
#else
#define dump(x)
#endif

typedef long long int ll;
typedef pair<int,int> pii;
//template<typename T> using vec=std::vector<T>;

const int inf=1<<30;
const long long int infll=1LL<<58;
const double eps=1e-9;
const int dx[]={1,0,-1,0},dy[]={0,1,0,-1};

template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec){
	os << "[";
	for (const auto &v : vec) {
		os << v << ",";
	}
	os << "]";
	return os;
}

int p,q,a,n;

int dfs(int denom,int numer,int prev,int product,int num){
    {
        int tmp1=denom*prev,tmp2=numer*prev+denom*num;
        if((double)tmp2/tmp1+eps<(double)p/q) return 0;
    }
    if((double)numer/denom-eps>(double)p/q) return 0;

    int res=0;
    if((double)p/q-eps<=(double)numer/denom  and (double)numer/denom<=(double)p/q+eps) ++res;
    if(num==0) return res;

    int x=prev;
    while(true){
        if(product*x>a) break;
        res+=dfs(denom*x,numer*x+denom,x,product*x,num-1);
        ++x;
    }
    return res;
}

void solve(){
    while(cin >> p >> q >> a >> n){
        if(p==0 and q==0 and a==0 and n==0) break;
        cout << dfs(1,0,1,1,n) << endl;
    }
}

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	solve();
	return 0;
}

Problem C: Unit Fraction Partition

A fraction whose numerator is 1
and whose denominator is a positive integer
is called a unit fraction.
A representation of a positive rational number
p/q
as the sum of finitely many unit fractions is called a partition of
p/q
into unit fractions.
For example,
1/2 + 1/6
is a partition of
2/3
into unit fractions.
The difference in the order of addition is disregarded.
For example, we do not distinguish
1/6 + 1/2
from
1/2 + 1/6.

For given four positive integers
p,
q,
a, and
n,
count the number
of partitions of
p/q
into unit fractions satisfying the following two conditions.

The partition is the sum of at most
n
many unit fractions.

The product of the denominators of the unit fractions in the
partition is less than or equal to
a.

For example, if
(p,q,a,n) = (2,3,120,3),
you should report 4 since

enumerates all of the valid partitions.

Input

The input is a sequence of at most 1000 data sets followed by a terminator.

A data set is a line containing four positive integers
p,
q,
a, and
n
satisfying
p,q <= 800,
a <= 12000
and
n <= 7.
The integers are separated by a space.

The terminator is composed of just one line
which contains four zeros separated by a space.
It is not a part of the input data but a mark for the end of the input.

Output

The output should be composed of lines
each of which contains a single integer.
No other characters should appear in the output.

The output integer corresponding to a data set
p,
q,
a,
n
should be the number of all partitions of
p/q
into at most
n
many unit fractions such that the product of the denominators of the
unit fractions is less than or equal to
a.

Sample Input

2 3 120 3
2 3 300 3
2 3 299 3
2 3 12 3
2 3 12000 7
54 795 12000 7
2 3 300 1
2 1 200 5
2 4 54 2
0 0 0 0

Output for the Sample Input

4
7
6
2
42
1
0
9
3


#include<iostream>
using namespace std;
const double eps=1e-9;
double p,q,a;
int n;
int ans=0;
void dfs(double pq,int s,int depth,int seki){
  if(pq>=-eps&&pq<=eps){
    ans++;
    return;
  }
  for(int i=s;i<=a/2;i++){
    if(seki*i>a)
      break;
    if((pq-(1.0/i))>=-eps&&depth+1<=n){
      dfs((pq-(1.0/i)),i,depth+1,seki*i);
    }
  }
}
int main(){
  while(cin>>p>>q>>a>>n,p+q+a+n){
    ans=0;
    for(int i=1;i<=a/2;i++){
      if((p/q)-(1.0/i)>=-eps)
	dfs((p/q)-(1.0/i),i,1,i);
    }
    cout<<ans<<endl;
  }
  return 0;
}


#include <iostream>
#include <queue>
#include <unordered_set>

struct Action {
	size_t x;
	size_t y;
	size_t cost;
	bool left_foot_on;
};

bool operator>(Action lhs, Action rhs) {
	return lhs.cost > rhs.cost;
}

bool operator==(Action lhs, Action rhs) {
	return lhs.x == rhs.x && lhs.y == rhs.y && lhs.left_foot_on == rhs.left_foot_on;
}

namespace std {
	template <>
	struct hash<Action> {
		using result_type = size_t;

		result_type operator()(const Action& act) const {
			return act.x * 31 + act.y * 12 + act.left_foot_on * 7;
		}
	};
}

class Climber {
private:
	using candidates_t = std::priority_queue<Action, std::vector<Action>, std::greater<Action>>;

	size_t _width;
	size_t _height;
	std::string* _cliff;
	candidates_t _candidates;
	std::unordered_set<Action> _traversed;

	char get(size_t x, size_t y);
	void try_put_candidate(const Action& now, size_t x, size_t y);
	void put_candidate(size_t x, size_t y, size_t cost, bool left_foot_on);
public:
	Climber(size_t width, size_t height);
	void load();
	int climb();
};

Climber::Climber(size_t width, size_t height) : _width(width), _height(height) { }

void Climber::load() {
	_cliff = new std::string[_height];
	for (size_t y = 0; y < _height; ++y) {
		std::string line;
		for (size_t x = 0; x < _width; ++x) {
			char a;
			std::cin >> a;
			line += a;
		}
		_cliff[y] = line;
	}
}

int Climber::climb() {
	// ??????????????????S????????????????¶????????¶???????????????????????????????
	for (size_t y = 0; y < _height; ++y) {
		for (size_t x = 0; x < _width; ++x) {
			if (get(x, y) == 'S') {
				put_candidate(x, y, 0, false);
				put_candidate(x, y, 0, true);
			}
		}
	}
	// ???????°???????????????????????????????????????????????????????????????????
	while (!_candidates.empty()) {
		const Action now = _candidates.top();
		if (get(now.x, now.y) == 'T') {
			return now.cost;
		}
		_candidates.pop();
#ifdef _DEBUG
		//std::cerr << "(" << now.x << "," << now.y << ")->" << now.cost << " [" << now.left_foot_on << "]\n";
#endif
		if (now.left_foot_on) {
			try_put_candidate(now, now.x + 1, now.y - 2);
			try_put_candidate(now, now.x + 1, now.y - 1);
			try_put_candidate(now, now.x + 1, now.y);
			try_put_candidate(now, now.x + 1, now.y + 1);
			try_put_candidate(now, now.x + 1, now.y + 2);
			try_put_candidate(now, now.x + 2, now.y - 1);
			try_put_candidate(now, now.x + 2, now.y);
			try_put_candidate(now, now.x + 2, now.y + 1);
			try_put_candidate(now, now.x + 3, now.y);
		} else {
			try_put_candidate(now, now.x - 1, now.y - 2);
			try_put_candidate(now, now.x - 1, now.y - 1);
			try_put_candidate(now, now.x - 1, now.y);
			try_put_candidate(now, now.x - 1, now.y + 1);
			try_put_candidate(now, now.x - 1, now.y + 2);
			try_put_candidate(now, now.x - 2, now.y - 1);
			try_put_candidate(now, now.x - 2, now.y);
			try_put_candidate(now, now.x - 2, now.y + 1);
			try_put_candidate(now, now.x - 3, now.y);
		}
	}
	// ????????????????????£???
	return -1;
}

void Climber::try_put_candidate(const Action& now, size_t x, size_t y) {
	char type = get(x, y);
	if (type == 'S' || type == 'X' || type == '\0') {
		return; // type==S??????????????????????????????????????????????§????????????????????????????????????????????????????
	}
	int additionalCost;
	if (type == 'T') {
		additionalCost = 0; // ????????§??????????????????
	} else {
		additionalCost = type - '0';
	}
	put_candidate(x, y, now.cost + additionalCost, !now.left_foot_on);
}

char Climber::get(size_t x, size_t y) {
	if (x >= _width || y >= _height) {
		return '\0'; // invalid range
	}
	return _cliff[y][x];
}

void Climber::put_candidate(size_t x, size_t y, size_t cost, bool left_foot_on) {
	Action a{x, y, cost, left_foot_on};
	auto alreadyTraversed = _traversed.find(a);
	if (alreadyTraversed == _traversed.end() || alreadyTraversed->cost > cost) {
		_traversed.emplace(a);
		_candidates.emplace(std::move(a));
	}
}

int main() {
	size_t width, height;
	while (true) {
		std::cin >> width >> height;
		if (width == 0 || height == 0) {
			break;
		}
		Climber climber(width, height);
		climber.load();
		std::cout << climber.climb() << std::endl;
	}
}

Problem D: Cliff Climbing

At 17:00, special agent Jack starts to escape from the enemy camp.
There is a cliff in between the camp and the nearest safety zone.
Jack has to climb the almost vertical cliff
by stepping his feet on the blocks that cover the cliff.
The cliff has slippery blocks where Jack has to
spend time to take each step.
He also has to bypass some blocks that are too loose to support his weight.
Your mission is to write a program that calculates the minimum time to complete climbing.

Figure D-1 shows an example of cliff data that you will
receive.
The cliff is covered with square blocks.
Jack starts cliff climbing from the ground under the cliff,
by stepping his left or right foot on one of the blocks marked with
'S' at the bottom row.
The numbers on the blocks are the "slippery levels". It takes
t time units for him to safely put his foot on a
block marked with t, where 1 ≤ t ≤ 9.
He cannot put his feet on blocks marked with 'X'.
He completes the climbing when he puts
either of his feet on one of the blocks marked with 'T' at the top row.

Figure D-1: Example of Cliff Data

Jack's movement must meet the following constraints.
After putting his left (or right) foot on a block, he can only move
his right (or left, respectively) foot.
His left foot position (lx, ly) and his right foot position
(rx, ry) should satisfy
lx < rx
and | lx - rx | + | ly - ry | ≤ 3
.
This implies that, given a position of his left foot in Figure D-2 (a), he has to
place his right foot on one of the nine blocks marked with blue color.
Similarly, given a position of his right foot in Figure D-2 (b),
he has to place his
left foot on one of the nine blocks marked with blue color.

Figure D-2: Possible Placements of Feet

Input

The input is a sequence of datasets.
The end of the input is indicated by a line containing two zeros separated by a space.
Each dataset is formatted as follows:

w h

s(1,1) ... s(1,w)

s(2,1) ... s(2,w)

...

s(h,1) ... s(h,w)

The integers w and h are the width and the height of
the matrix data of the cliff. You may assume 2 ≤ w ≤ 30 and 5 ≤ h ≤ 60.
Each of the following h lines consists of w characters
delimited by a space.
The character s(y, x) represents the state of the block at
position
(x, y) as follows:

'S': Jack can start cliff climbing from this block.

'T': Jack finishes climbing when he reaches this block.

'X': Jack cannot put his feet on this block.

'1' - '9' (= t): Jack has to spend t time units
to put either of his feet on this block.

You can assume that it takes no time to put a foot on a block marked with 'S' or 'T'.

Output

For each dataset, print a line only having a decimal integer indicating
the minimum time required for the cliff climbing,
when Jack can complete it.
Otherwise, print a line only having "-1" for the dataset.
Each line should not have any characters other than these numbers.

Sample Input

6 6
4 4 X X T T
4 7 8 2 X 7
3 X X X 1 8
1 2 X X X 6
1 1 2 4 4 7
S S 2 3 X X
2 10
T 1
1 X
1 X
1 X
1 1
1 X
1 X
1 1
1 X
S S
2 10
T X
1 X
1 X
1 X
1 1
1 X
1 X
1 1
1 X
S S
10 10
T T T T T T T T T T
X 2 X X X X X 3 4 X
9 8 9 X X X 2 9 X 9
7 7 X 7 3 X X 8 9 X
8 9 9 9 6 3 X 5 X 5
8 9 9 9 6 X X 5 X 5
8 6 5 4 6 8 X 5 X 5
8 9 3 9 6 8 X 5 X 5
8 3 9 9 6 X X X 5 X
S S S S S S S S S S
10 7
2 3 2 3 2 3 2 3 T T
1 2 3 2 3 2 3 2 3 2
3 2 3 2 3 2 3 2 3 4
3 2 3 2 3 2 3 2 3 5
3 2 3 1 3 2 3 2 3 5
2 2 3 2 4 2 3 2 3 5
S S 2 3 2 1 2 3 2 3
0 0

Output for the Sample Input

12
5
-1
22
12


#define _CRT_SECURE_NO_WARNINGS
// #define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// #define int ll
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> pii;
#define all(c) begin(c), end(c)
#define range(i,a,b) for(ll i=a; i<ll(b); i++)
#define rep(i,b) range(i,0,b)
#define rangei(i,a,b) for(ll a=a;i<=ll(b);i++)
#define repi(i,b) rangei(i,1,b)
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
template<class T> ostream & operator << (ostream &os, vector<T> const &);
template<int n, class...T>
typename enable_if<(n>=sizeof...(T))>::type
_ot(ostream &, tuple<T...> const &){}
template<int n, class...T>
typename enable_if<(n< sizeof...(T))>::type
_ot(ostream &os, tuple<T...> const &t){
    os << (n==0?"":" ") << get<n>(t); _ot<n+1>(os, t);
}
template<class...T>
ostream & operator << (ostream &os, tuple<T...> const &t){
    _ot<0>(os, t); return os;
}
template<class T, class U>
ostream & operator<<(ostream &os, pair<T,U> const &p){
    return os << "(" << p.first << ", " << p.second << ") ";
}
template<class T>
ostream & operator<<(ostream &os, vector<T> const &v){
    rep(i,v.size()) os << v[i] << (i+1==(int)v.size()?"":" "); return os;
}
#ifdef DEBUG
#define dump(...) (cerr << #__VA_ARGS__ << " = " << mt(__VA_ARGS__) \
                   << " [" << __LINE__ << "]" << endl)
#else
#define dump(...)
#endif
void fastios(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);
#define endl '\n'
}
template<class T>
size_t uniq(vector<T> &v){
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
    return v.size();
}
template<class T>
size_t uniq(T *l, size_t n){
    sort(l,l+n);
    return unique(l,l+n) - l;
}
#define mems(arr,val) memset(arr,val,sizeof(arr));
int const mod = 1000000007;
int const inf = numeric_limits<int>::max()/8;

typedef int Capacity;
struct Edge {
    int src, dst;
    Capacity cap;
    Edge(int src_, int dst_, Capacity cap_) :
        src(src_), dst(dst_), cap(cap_) { }
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

struct Dinic {
    int n, s, t;
    vector<int> level, iter;
    vector<vector<Capacity>> cap, flow;
    vector<vector<int>> g;
    Capacity inf;
    Dinic(int n)
        : n(n), cap(n, vector<Capacity>(n)), flow(n, vector<Capacity>(n)),
          g(n, vector<int>()), inf(numeric_limits<Capacity>::max()/8){}
    Dinic(const Graph &graph){
        *this = Dinic(graph.size());
        rep(i,n) for(auto &e : graph[i]) addEdge(e.src, e.dst, e.cap);
    }
    void addEdge(int u, int v, Capacity c){
        cap[u][v] += c; cap[v][u] += c; flow[v][u] += c;
        g[u].push_back(v); g[v].push_back(u);
    }
    inline Capacity residue(int u, int v){ return cap[u][v] - flow[u][v]; }
    Capacity solve(int s, int t){
        this->t = t, this->s = s;
        Capacity res = 0, aug = 1;
        while(aug > 0){
            levelize();
            iter.assign(n, 0);
            aug = augment(s, inf);
            res += aug;
        }
        return res;
    }
    void levelize(){
        level.assign(n, inf); level[s] = 0;
        queue<int> q; q.emplace(s);
        while(q.size()){
            int v = q.front(); q.pop();
            for(const int &d : g[v]){
                if(level[d] <= level[v] + 1 || residue(v,d) == 0) continue;
                level[d] = level[v] + 1; q.emplace(d);
            }
        }
    }
    Capacity augment(int v, Capacity lim){
        Capacity res = 0;
        if(v == t) return lim;
        for(int &i = iter[v]; i < (int)g[v].size(); i++){
            const int &d = g[v][i];
            if(residue(v,d) == 0 || level[v] + 1 != level[d]) continue;
            Capacity aug = augment(d, min(lim, residue(v,d)));
            if(aug > 0){
                flow[v][d] += aug; flow[d][v] -= aug;
                res += aug; lim -= aug;
                if(lim == 0) return res;
            }
        }
        return res;
    }
};

int main(){
    fastios();
    int n,m;
    while(cin >> n >> m && n|m){
        vector<int> a(n), b(m);
        rep(i,n) cin >> a[i];
        rep(i,m) cin >> b[i];
        Dinic d(n+m+2);
        int s = n+m, t = n+m+1;
        rep(i,m) d.addEdge(i+n,t,1);
        rep(i,n){
            d.addEdge(s,i,1);
            rep(j,m) if(__gcd(a[i],b[j]) != 1) d.addEdge(i,n+j,1);
        }
        rep(i,n)rep(j,m){
            if(d.flow[i][j+n]) dump(i,j, d.flow[i][j+m]);
        }
        cout << d.solve(s,t) << endl;
    }
}

// int main(){
//     int N,M;
//     cin >> N >> M;
//     Graph g(N);
//     rep(i,M){
//         int a,b,c;
//         cin >> a >> b >> c;
//         g[a].emplace_back(a,b,c);
//     }
//     Dinic dinic(g);
//     cout << dinic.solve(0,N-1) << endl;
// }

Problem E: Cards

There are many blue cards and red cards on the table.
For each card, an integer number greater than 1 is printed on its face.
The same number may be printed on several cards.

A blue card and a red card can be paired when both of the numbers
printed on them have a common divisor greater than 1.
There may be more than one red card that can be paired with one blue card.
Also, there may be more than one blue card that can be paired with one red card.
When a blue card and a red card are chosen and paired,
these two cards are removed from the whole cards on the table.

Figure E-1: Four blue cards and three red cards

For example, in Figure E-1,
there are four blue cards and three red cards.
Numbers 2, 6, 6 and 15 are printed on the faces of the four blue cards,
and 2, 3 and 35 are printed on those of the three red cards.
Here, you can make pairs of blue cards and red cards as follows.
First,
the blue card with number 2 on it and the red card with 2 are paired and removed.
Second,
one of the two blue cards with 6 and the red card with 3 are paired and removed.
Finally,
the blue card with 15 and the red card with 35 are paired and removed.
Thus the number of removed pairs is three.

Note that the total number of the pairs depends on
the way of choosing cards to be paired.
The blue card with 15 and the red card with 3 might be paired
and removed at the beginning.
In this case, there are only one more pair that can be removed
and the total number of the removed pairs is two.

Your job is to find the largest number of pairs that can be removed from the given set of cards on the table.

Input

The input is a sequence of datasets.
The number of the datasets is less than or equal to 100.
Each dataset is formatted as follows.

m n

b1 ... bk
... bm

r1 ... rk
... rn

The integers m and n are the number of blue cards
and that of red cards, respectively.
You may assume 1 ≤ m ≤ 500 and 1≤ n ≤ 500.

bk (1 ≤ k ≤ m) and
rk (1 ≤ k ≤ n) are
numbers printed on the blue cards and the red cards respectively,
that are integers greater than or equal to 2 and less than
10000000 (=107).
The input integers are separated by a space or a newline.
Each of bm and rn is
followed by a newline.
There are no other characters in the dataset.

The end of the input is indicated by a line containing two zeros
separated by a space.

Output

For each dataset, output a line containing an integer that indicates
the maximum of the number of the pairs.

Sample Input

4 3
2 6 6 15
2 3 5
2 3
4 9
8 16 32
4 2
4 9 11 13
5 7
5 5
2 3 5 1001 1001
7 11 13 30 30
10 10
2 3 5 7 9 11 13 15 17 29
4 6 10 14 18 22 26 30 34 38
20 20
195 144 903 63 137 513 44 626 75 473
876 421 568 519 755 840 374 368 570 872
363 650 155 265 64 26 426 391 15 421
373 984 564 54 823 477 565 866 879 638
100 100
195 144 903 63 137 513 44 626 75 473
876 421 568 519 755 840 374 368 570 872
363 650 155 265 64 26 426 391 15 421
373 984 564 54 823 477 565 866 879 638
117 755 835 683 52 369 302 424 513 870
75 874 299 228 140 361 30 342 750 819
761 123 804 325 952 405 578 517 49 457
932 941 988 767 624 41 912 702 241 426
351 92 300 648 318 216 785 347 556 535
166 318 434 746 419 386 928 996 680 975
231 390 916 220 933 319 37 846 797 54
272 924 145 348 350 239 563 135 362 119
446 305 213 879 51 631 43 755 405 499
509 412 887 203 408 821 298 443 445 96
274 715 796 417 839 147 654 402 280 17
298 725 98 287 382 923 694 201 679 99
699 188 288 364 389 694 185 464 138 406
558 188 897 354 603 737 277 35 139 556
826 213 59 922 499 217 846 193 416 525
69 115 489 355 256 654 49 439 118 961
0 0

Output for the Sample Input

3
1
0
4
9
18
85


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>

using namespace std;

struct dice{
	int val[6];
	void roti(){
		int t=val[5];
		val[5]=val[1];
		val[1]=val[4];
		val[4]=val[0];
		val[0]=t;
	}
	void rotj(){
		int t=val[3];
		val[3]=val[1];
		val[1]=val[2];
		val[2]=val[0];
		val[0]=t;
	}
	void rotk(){
		int t=val[3];
		val[3]=val[4];
		val[4]=val[2];
		val[2]=val[5];
		val[5]=t;
	}
};

int f[3][3],t[3][3];
dice cube[3][3][3];
int n;
bool res[55];

void rec(int cur){
	if(cur==27){
		int sum=0;
		for(int i=0;i<3;i++){
			for(int k=0;k<3;k++){
				sum+=cube[i][2][k].val[4];
			}
		}
		res[0]=false;
		res[sum]=true;
		return;
	}
	int k=cur/9;
	int i=(cur/3)%3;
	int j=cur%3;
	dice d=(dice){2,5,6,1,3,4};
	for(int r=0;r<24;r++){
		d.rotk();
		if(r%4==0){
			if(r<16)d.rotj();
			else if(r==16)d.roti();
			else{
				for(int l=0;l<2;l++){
					d.roti();
				}
			}
		}
		if(k==0 && t[i][j] && t[i][j]!=d.val[0])continue;
		if(i==2 && f[k][j] && f[k][j]!=d.val[2])continue;
		if(i && cube[i-1][j][k].val[2]+d.val[3]!=7)continue;
		if(j && cube[i][j-1][k].val[4]+d.val[5]!=7)continue;
		if(k && cube[i][j][k-1].val[1]+d.val[0]!=7)continue;
		cube[i][j][k]=d;
		rec(cur+1);
	}
}

void solve(){
	memset(res,false,sizeof(res));
	res[0]=true;
	rec(0);
	if(res[0])printf("0\n");
	else{
		bool c=false;
		for(int i=1;i<=54;i++){
			if(res[i]){
				if(c)printf(" ");
				c=true;
				printf("%d",i);
			}
		}
		printf("\n");
	}
}

int main(void){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		for(int j=0;j<3;j++){
			for(int k=0;k<3;k++){
				scanf("%d",&t[j][k]);
			}
		}
		for(int j=0;j<3;j++){
			for(int k=0;k<3;k++){
				scanf("%d",&f[j][k]);
			}
		}
		solve();
	}
	return 0;
}

Problem F: Dice Puzzle

Let’s try a dice puzzle. The rules of this puzzle are as follows.

Dice with six faces as shown in Figure 1 are used in the puzzle.

Figure 1: Faces of a die

With twenty seven such dice, a 3 × 3 × 3 cube is built as shown in Figure 2.

Figure 2: 3 × 3 × 3 cube

When building up a cube made of dice, the sum of the numbers marked on the faces of adjacent dice that are placed against each other must be seven (See Figure 3). For example, if one face of the pair is marked “2”, then the other face must be “5”.

Figure 3: A pair of faces placed against each other

The top and the front views of the cube are partially given, i.e. the numbers on faces of
some of the dice on the top and on the front are given.

Figure 4: Top and front views of the cube

The goal of the puzzle is to find all the plausible dice arrangements that are consistent
with the given top and front view information.

Your job is to write a program that solves this puzzle.

Input

The input consists of multiple datasets in the following format.

N
Dataset1
Dataset2
...
DatasetN

N is the number of the datasets.

The format of each dataset is as follows.

T11 T12 T13
T21 T22 T23
T31 T32 T33
F11 F12 F13
F21 F22 F23
F31 F32 F33

Tij and Fij (1 ≤ i ≤ 3, 1 ≤ j ≤ 3) are the faces of dice appearing on the top and front views,
as shown in Figure 2, or a zero. A zero means that the face at the corresponding position is
unknown.

Output

For each plausible arrangement of dice, compute the sum of the numbers marked on the nine
faces appearing on the right side of the cube, that is, with the notation given in Figure 2,

∑3i=1∑3j=1Rij.

For each dataset, you should output the right view sums for all the plausible arrangements, in
ascending order and without duplicates. Numbers should be separated by a single space.

When there are no plausible arrangements for a dataset, output a zero.

For example, suppose that the top and the front views are given as follows.

Figure 5: Example

There are four plausible right views as shown in Figure 6. The right view sums are 33, 36, 32,
and 33, respectively. After rearranging them into ascending order and eliminating duplicates,
the answer should be “32 33 36”.

Figure 6: Plausible right views

The output should be one line for each dataset. The output may have spaces at ends of lines.

Sample Input

4
1 1 1
1 1 1
1 1 1
2 2 2
2 2 2
2 2 2
4 3 3
5 2 2
4 3 3
6 1 1
6 1 1
6 1 0
1 0 0
0 2 0
0 0 0
5 1 2
5 1 2
0 0 0
2 0 0
0 3 0
0 0 0
0 0 0
0 0 0
3 0 1

Output for the Sample Input

27
24
32 33 36
0


#include<bits/stdc++.h>
using namespace std;
int main(){
  int sum=0;
  string s,t;
  cin>>s>>t;
swap(s,t);
  vector<string>v[4001];
  for(int i=0;i<s.size();i++)
    for(int j=1;j+i<=s.size();j++){
      string p=s.substr(i,j);
      sort(p.begin(),p.end());
      if(find(v[j].begin(),v[j].end(),p)==v[j].end())
       v[j].push_back(p);
    }

  for(int i=0;i<4001;i++)
    sort(v[i].begin(),v[i].end());

  for(int i=0;i<t.size();i++)
    for(int j=1;j+i<=t.size();j++){
      string p=t.substr(i,j);
      sort(p.begin(),p.end());
      int l=0,r=v[p.size()].size();
      while(l<r){
        int mid=(l+r)/2;
        string vv=v[p.size()][mid];
        if(vv==p){
          sum=max(sum,(int)p.size());
          break;
        }
        else if(vv>p)r=mid;
        else l=mid+1;
      }

    }
  cout<<sum<<endl;
}

MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

Problem D
Hidden Anagrams

An anagram is a word or a phrase that is formed by rearranging the letters of another. For instance, by rearranging the letters of "William Shakespeare," we can have its anagrams "I am a weakish speller," "I'll make a wise phrase," and so on. Note that when $A$ is an anagram of $B$, $B$ is an anagram of $A$.

In the above examples, differences in letter cases are ignored, and word spaces and punctuation symbols are freely inserted and/or removed. These rules are common but not applied here; only exact matching of the letters is considered.

For two strings $s_1$ and $s_2$ of letters, if a substring $s'_1$ of $s_1$ is an anagram of a substring $s'_2$ of $s_2$, we call $s'_1$ a hidden anagram of the two strings, $s_1$ and $s_2$. Of course, $s'_2$ is also a hidden anagram of them.

Your task is to write a program that, for given two strings, computes the length of the longest hidden anagrams of them.

Suppose, for instance, that "anagram" and "grandmother" are given. Their substrings "nagr" and "gran" are hidden anagrams since by moving letters you can have one from the other. They are the longest since any substrings of "grandmother" of lengths five or more must contain "d" or "o" that "anagram" does not. In this case, therefore, the length of the longest hidden anagrams is four. Note that a substring must be a sequence of letters occurring consecutively in the original string and so "nagrm" and "granm" are not hidden anagrams.

Input

The input consists of a single test case in two lines.

$s_1$

$s_2$

$s_1$ and $s_2$ are strings consisting of lowercase letters (a through z) and their lengths are between 1 and 4000, inclusive.

Output

Output the length of the longest hidden anagrams of $s_1$ and $s_2$. If there are no hidden anagrams, print a zero.

Sample Input 1

anagram
grandmother

Sample Output 1

4

Sample Input 2

williamshakespeare
iamaweakishspeller

Sample Output 2

18

Sample Input 3

aaaaaaaabbbbbbbb
xxxxxabababxxxxxabab

Sample Output 3

6

Sample Input 4

abababacdcdcd
efefefghghghghgh

Sample Output 4

0


#include <bits/stdc++.h>

using namespace std;

bool issquare(vector<string> m, vector<char> &c, int k){
	if(k >= c.size()){
		return true;
	}
	int n = (int)c.size();
	int h = (int)m.size();
	int w = (int)m[0].size();
	int r = 0, l = w, u = h, d = 0;
	for(int i = 0; i < h; i++){
		for(int j = 0; j < w; j++){
			if(m[i][j] == c[k]){
				r = max(r, j);
				l = min(l, j);
				u = min(u, i);
				d = max(d, i);
			}
		}
	}
	//printf("(%d, %d), (%d, %d)\n",r,l,u,d);
	bool flag = true;
	for(int i = u; i <= d; i++){
		for(int j = l; j <= r; j++){
			if(m[i][j] != '?' && m[i][j] != c[k]){
				flag = false;
				i = j = (int)1e9;
			}
		}
	}
	if(!flag)return false;
	for(int i = u; i <= d; i++){
		for(int j = l; j <= r; j++){
			if(m[i][j] == c[k]){
				m[i][j] = '?';
			}
		}
	}
	return issquare(m, c, k+1);
}

int main(){
	int nn; cin >> nn;
	for(int z = 0; z < nn; z++){
		int h,w; cin >> h >> w;
		vector<string> m(h);
		vector<char> c;
		for(int i = 0; i < h; i++){
			cin >> m[i];
		}
		for(int i = 0; i < h; i++){
			for(int j = 0; j < w; j++){
				if(m[i][j] == '.')continue;
				bool flag1 = true;
				for(int k = 0; k < c.size(); k++){
					if(m[i][j] == c[k]){
						flag1 = false;
						break;
					}
				}
				if(flag1)c.push_back(m[i][j]);
			}
		}
		sort(c.begin(), c.end());/*
		for(int i = 0; i < c.size(); i++){
			cout << c[i] << " ";
		}
		cout << endl;*/
		bool flag = false;
		do{
			if(issquare(m, c, 0)){
				flag = true;
				break;
			}
		}while(next_permutation(c.begin(), c.end()));
		if(flag){
			cout << "SAFE" << endl;
		}
		else{
			cout << "SUSPICIOUS" << endl;
		}
	}
	return 0;
}

X-Ray Screening System

これは 20XX 年の話である．再生発電網による安定したエネルギー供給，および液化合成燃料の発明によって航空旅客数は鰻登りに増加した．しかし，航空機によるテロリズムの脅威は依然として存在するため，高速でかつ高い信頼性をもつ自動手荷物検査システムの重要性が高まっている．検査官が全部の荷物を調べることは実際問題として困難であることから，自動検査において疑わしいと判断された手荷物だけを検査官で改めて調べるという仕組みを整えたいわけである．

航空機業界からの要請を受け，国際客室保護会社（International Cabin Protection Company）では，新たな自動検査システムを開発するため，最近の旅客の手荷物について調査した．調査の結果，最近の旅客の手荷物には次のような傾向があることが判明した．

手荷物は 1 辺だけが短い直方体のような形状をしている．

一般の乗客が手荷物に詰めて航空機に持ち込む品物としてはノートパソコン，音楽プレイヤー，携帯ゲーム機，トランプなどがあり，これらはいずれも長方形である．

個々の品物は，その長方形の辺が手荷物の辺と平行になるように詰めこまれる．

一方，テロリズムに用いられるような武器は，長方形とは非常に異なる形状をもつ．

上記の調査結果をふまえて，以下のような手荷物検査のためのモデルを考案した．それぞれの手荷物は X 線に対して透明である直方体の容器だとみなす．その中には X 線に対して不透明である複数の品物が入っている．ここで，直方体の 3 辺を x 軸，y 軸，z 軸とする座標系を考え，x 軸と平行な方向に X 線を照射して，y-z 平面に投影された画像を撮影する．撮影された画像は適当な大きさの格子に分割され，画像解析によって，それぞれの格子領域に映っている品物の材質が推定される．この会社には非常に高度の解析技術があり，材質の詳細な違いすらも解析することが可能であることから，品物の材質は互いに異なると考えることができる．なお，複数の品物が x 軸方向に関して重なっているときは，それぞれの格子領域について最も手前にある，すなわち x 座標が最小である品物の材質が得られる．また，2 つ以上の品物の x 座標が等しいことはないと仮定する．

あなたの仕事は，画像解析の結果が与えられたときに，長方形ではない（武器であるかもしれない）品物が入っていることが断言できるか，あるいはその手荷物には長方形の品物以外のものは入っていないと推測されるかを判定するプログラムを作成することである．

Input

入力の先頭行には単一の正の整数が含まれ，これはデータセットの個数を表す．それぞれのデータセットは次の形式で与えられる．

H W

解析結果その1

解析結果その2

...

解析結果そのH

H は画像の縦の大きさ，W は横の大きさを表す整数である (1 <= h , w <= 50)．解析結果の各行は W 文字で構成されており，i 番目の文字は，行の左から i 番目にある格子領域における解析結果を表す．物質が検出された格子領域については，その材質が英大文字（A〜Z）によって表される．このとき，同じ材質であれば同じ文字が，また異なる材質であれば異なる文字が用いられる．物質が検出されなかった格子領域についてはドット（.）で表される．

すべてのデータセットについて，材質の種類は 7 種類を超えないことが保証されている．

Output

それぞれのデータセットに対して，長方形以外の品物が確実に入っているときは「SUSPICIOUS」を，そうでないときは「SAFE」をそれぞれ 1 行に出力しなさい．

Sample Input

6
1 1
.
3 3
...
.W.
...
10 10
..........
.DDDDCCC..
.DDDDCCC..
.DDDDCCC..
ADDDDCCC..
AAA..CCC..
AAABBBBC..
AAABBBB...
..BBBBB...
..........
10 10
..........
.DDDDDD...
.DDDDCCC..
.DDDDCCC..
ADDDDCCC..
AAA..CCC..
AAABBBBC..
AAABBBB...
..BBBBB...
..........
10 10
R..E..C.T.
R.EEE.C.T.
.EEEEE....
EEEEEEE...
.EEEEEEE..
..EEEEEEE.
...EEEEEEE
....EEEEE.
.....EEE..
......E...
16 50
..................................................
.........AAAAAAAAAAAAAAAA.........................
....PPP...AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.....
....PPP...AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.....
....PPP...AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA....
....PPP..............AAAAA.AAAAAAAAAAAAAAAA.......
....PPP................A....AAA.AAAAAAAAAA........
....PPP...........IIIIIAAIIAIII.AAAAAAAAAA........
..CCCCCCCCCCCCC...IIIIIIAAAAAAAAAAAAAAAAAA........
..CCCCCCCCCCCCC...IIIIIIIIIIIII...AAAAAAAAAA......
....PPP............................AAAAAAAAAA.....
MMMMPPPMMMMMMMMMMMMMMM.............AAAAAAAAAAA....
MMMMPPPMMMMMMMMMMMMMMM..............AAAAAAAAAAA...
MMMMMMMMMMMMMMMMMMMMMM...............AAAAAAAAAA...
MMMMMMMMMMMMMMMMMMMMMM...............AAAAAAAAAA...
MMMMMMMMMMMMMMMMMMMMMM............................

Output for the Sample Input

SAFE
SAFE
SAFE
SUSPICIOUS
SUSPICIOUS
SUSPICIOUS


#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100009
using namespace std;

int dp1[10009];
int dp2[10006];
char s[25];

int num[105];

int main()
{
    int n,m,x,y;
    while(scanf("%d",&n)&&n!=0)
    {
        int ma=-1;
        for(int i=0; i<n; i++)
            scanf("%d",&num[i]);
        sort(num,num+n);
        memset(dp1,0,sizeof dp1);
        memset(dp2,0,sizeof dp2);
        scanf("%d",&m);
        for(int i=0; i<m; i++)
        {
            scanf("%s",s);
            scanf("%d",&x);
            scanf("%s",s);
            scanf("%d",&y);
//        printf("%d %d\n",x,y);
            if(s[0]=='S')
            {
                for(int j=x; j<=10000; j++)
                    dp1[j]=max(dp1[j],dp1[j-x]+y);//single
            }
            else
            {
                for(int j=x; j<=10000; j++)
                    dp2[j]=max(dp2[j],dp2[j-x]+y);//all
            }
        }
        long long ans=(long long)1<<62,sum;
        for(int i=0; i<ans; i++)
        {
//            sum=lower_bound(dp2,dp2+10000,num[i])-dp2;
            sum=i;
//        printf("%d\n",tmp);
            for(int j=0; j<n; j++)
            {
                sum+=lower_bound(dp1,dp1+10000,num[j]-dp2[i])-dp1;
            }
            ans=min(ans,sum);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

Problem B: Magic Slayer

You are in a fantasy monster-ridden world. You are a slayer fighting against the monsters with magic
spells.

The monsters have hit points for each, which represent their vitality. You can decrease their hit points
by your magic spells: each spell gives certain points of damage, by which monsters lose their hit points,
to either one monster or all monsters in front of you (depending on the spell). Monsters are defeated
when their hit points decrease to less than or equal to zero. On the other hand, each spell may consume
a certain amount of your magic power. Since your magic power is limited, you want to defeat monsters
using the power as little as possible.

Write a program for this purpose.

Input

The input consists of multiple datasets. Each dataset has the following format:

N

HP1

HP2

...

HPN

M

Name1 MP1 Target1 Damage1

Name2 MP2 Target2 Damage2

...

NameM MPM TargetM DamageM

N is the number of monsters in front of you (1 ≤ N ≤ 100); HPi is the hit points of the i-th monster
(1 ≤ HPi ≤ 100000); M is the number of available magic spells (1 ≤ M ≤ 100); Namej is the name
of the j-th spell, consisting of up to 16 uppercase and lowercase letters; MPj is the amount of magic
power consumed by the j-th spell (0 ≤ MPj ≤ 99); Targetj is either "Single" or "All", where these
indicate the j-th magic gives damage just to a single monster or to all monsters respectively; Damagej is
the amount of damage (per monster in case of "All") made by the j-th magic (0 ≤ Damagej ≤ 999999).

All the numbers in the input are integers. There is at least one spell that gives non-zero damage to
monsters.

The last dataset is followed by a line containing one zero. This line is not a part of any dataset and should not be processed.

Output

For each dataset, Print in a line the minimum amount of magic power consumed to defeat all the monsters in the input.

Sample Input

3
8000 15000 30000
3
Flare 45 Single 8000
Meteor 62 All 6000
Ultimate 80 All 9999
0

Output for the Sample Input

232


#include <iostream>
using namespace std;
#define MAX 1000
#define F_MAX 2000

int n;
int field[MAX][MAX];

struct futon{
	int x[2], y[2];
};

futon F[F_MAX];

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

bool dfs( int pos ){
	if( pos == n ) return true;
	bool rep = false;
	for( int i = 0; i < 2; i++ ){
		int legx, legy, headx, heady;
		legx = F[pos].x[i];
		legy = F[pos].y[i];
		headx = F[pos].x[1-i];
		heady = F[pos].y[1-i];
		//cout << "----" << pos << "------" << endl;
		//cout << legx << " " << legy << " " << headx << " " << heady << endl;
		bool ok = true;
		for( int j = 0; j < 4; j++ ){
			if( (0 <= legx+dx[j] && legx+dx[j] < MAX) && (0 <= legy+dy[j] && legy+dy[j] < MAX) ){
				if( field[legx+dx[j]][legy+dy[j]] == 1 ) ok = false;
			}
			if( (0 <= headx+dx[j] && headx+dx[j] < MAX) && (0 <= heady+dy[j] && heady+dy[j] < MAX) ){
				if( field[headx+dx[j]][heady+dy[j]] == 2 ) ok = false;
			}
		}
		if( !ok ) continue;
		field[headx][heady] = 1;
		field[legx][legy] = 2;
		if( dfs(pos+1) ) rep = true;
		field[headx][heady] = 0;
		field[legx][legy] = 0;
	}
	return rep;
}

int main(){
	while( cin >> n, n ){
		for( int i = 0; i < n; i++ ){
			int x, y;
			char d;
			cin >> x >> y >> d;
			F[i].x[0] = x;
			F[i].y[0] = y;
			F[i].x[1] = (d == 'x') ? x+1 : x;
			F[i].y[1] = (d == 'x') ? y : y+1;
		}
		for( int j = 0; j < MAX; j++ ){
			for( int k = 0; k < MAX; k++ ){
				field[j][k] = 0;
			}
		}
		/*for( int i = 0; i < n; i++ ){
			for( int j = 0; j < 2; j++ ){
				cout << F[i].x[j] << " " << F[i].y[j] << " ";
			}
			cout << endl;
		}*/
		if( dfs(0) ) cout << "Yes" << endl;
		else cout << "No" << endl;
	}
}

Problem D: Futon

The sales department of Japanese Ancient Giant Corp. is visiting a hot spring resort for their
recreational trip. For deepening their friendships, they are staying in one large room of a
Japanese-style hotel called a ryokan.

In the ryokan, people sleep in Japanese-style beds called futons. They all have put their futons
on the floor just as they like. Now they are ready for sleeping but they have one concern: they
don’t like to go into their futons with their legs toward heads — this is regarded as a bad custom
in Japanese tradition. However, it is not obvious whether they can follow a good custom. You
are requested to write a program answering their question, as a talented programmer.

Here let's model the situation. The room is considered to be a grid on an xy-plane. As usual,
x-axis points toward right and y-axis points toward up. Each futon occupies two adjacent cells.
People put their pillows on either of the two cells. Their heads come to the pillows; their foots
come to the other cells. If the cell of some person's foot becomes adjacent to the cell of another
person's head, regardless their directions, then it is considered as a bad case. Otherwise people
are all right.

Input

The input is a sequence of datasets. Each dataset is given in the following format:

n

x1 y1 dir1

...

xn yn dirn

n is the number of futons (1 ≤ n ≤ 20,000); (xi, yi) denotes the coordinates of the left-bottom
corner of the i-th futon; diri is either 'x' or 'y' and denotes the direction of the i-th futon,
where 'x' means the futon is put horizontally and 'y' means vertically. All coordinate values are
non-negative integers not greater than 109 .

It is guaranteed that no two futons in the input overlap each other.

The input is terminated by a line with a single zero. This is not part of any dataset and thus
should not be processed.

Output

For each dataset, print "Yes" in a line if it is possible to avoid a bad case, or "No" otherwise.

Sample Input

4
0 0 x
2 0 x
0 1 x
2 1 x
4
1 0 x
0 1 x
2 1 x
1 2 x
4
0 0 x
2 0 y
0 1 y
1 2 x
0

Output for the Sample Input

Yes
No
Yes


#include <iostream>
#include <climits>
#include <algorithm>
using namespace std;

#define p(x) (x)*(x)

int round(int x)
{
  if(x > 255) return 255;
  else if(x < 0) return 0;
  else return x;
}

int main()
{
  while(1){
    int N, M;
    cin >> N >> M;
    if(N == 0 && M == 0) break;
    int C[M], x[N];
    for(int i = 0; i < M; i++)
      cin >> C[i];
    for(int i = 0; i < N; i++)
      cin >> x[i];
    int a[256];
    fill(a,a+256,INT_MAX);
    for(int i = 0; i < M; i++){
      int n = round(128+C[i]);
      a[n] = p(n-x[0]);
    }
    int b[256];
    for(int t = 1; t < N; t++){
      fill(b,b+256,INT_MAX);
      for(int i = 0; i < 256; i++){
        if(a[i] == INT_MAX) continue;
        for(int j = 0; j < M; j++){
          int n = round(i+C[j]);
          b[n] = min(b[n],a[i]+p(n-x[t]));
        }
      }
      copy(b,b+256,a);
    }
    cout << *min_element(a,a+256) << endl;
  }
}

Problem C: Differential Pulse Code Modulation

差分パルス符号変調は主に音声信号を圧縮する際に用いられる圧縮手法の一つである．

音声信号は計算機上では整数列(インパルス列)として扱われる．整数列は入力信号を一定時間間隔で標本化(サンプリング)し，振幅を記録したものである．一般にこの整数列は前後の値が近いという傾向がある．これを利用し，前後の値の差分を符号化し，圧縮率を向上させるのが差分パルス符号変調である．

本問題では差分の値をあらかじめ定められた値の集合から選ぶことを考える．この値の集合をコードブックと呼ぶことにする．復号化後の音声信号
yn は以下の式で定められる．

yn = yn
- 1 + C[kn]

ここで kn はプログラムによって出力される出力系列， C[j]
はコードブックの j 番目の値である．ただし yn
は加算によって0未満の値となった場合は0に，255より大きい値となった場合は255にそれぞれ丸められる．また， y0
の値は128とする．

あなたの仕事は，入力信号とコードブックが与えられたときに，元の入力信号と復号化後の出力信号との差の二乗和が最小となるように出力系列を選んで，そのときの差の二乗和を出力するプログラムを書くことである．

例えば，コードブックとして {4, 2, 1, 0, -1, -2, -4} という値のセットを使って
131, 137 という列を圧縮する場合，
y0 = 128,
y1 = 128 + 4 = 132,
y2 = 132 + 4 = 136 という列に圧縮すると
二乗和が (131 - 132)^2 + (137 - 136)^2 = 2 と最小になる．

また，同じくコードブックとして {4, 2, 1, 0, -1, -2, -4} という値のセットを使って
131, 123 という列を圧縮する場合，
y0 = 128,
y1 = 128 + 1 = 129,
y2 = 129 - 4 = 125 と，先程の例とは違って
131 により近づく +2 を採用しない方が
(131 - 129) ^ 2 + (123 - 125) ^ 2 = 8
というより小さな二乗和が得られる．

上記 2つの例は sample input の最初の 2例である．

Input

入力は複数のデータセットから構成される．各データセットの形式は次に示すとおりである．

N M

C1

C2

...

CM

x1

x2

...

xN

最初の行は，入力データセットの大きさを規定する． N は圧縮する入力信号の長さ(サンプル数)である． M
はコードブックに含まれる値の個数である． N 及び M は1 ≤ N ≤ 20000，1
≤ M ≤ 16を満たす．

これに続く M 行は，コードブックの記述である． Ci はコードブックに含まれる
i 番目の値を表す． Ci は-255 ≤ Ci
≤ 255を満たす．

これに続く N 行は，入力信号の記述である． xi は入力信号を表す整数列の i
番目の値である． xi は0 ≤ xi ≤ 255を満たす．

データセットの中の入力項目は，すべて整数である．入力の終りは，空白文字1個で区切られた2個のゼロのみからなる行で表される．

Output

入力の各データセットに対して， 元の入力信号と復号化後の出力信号との差の二乗和の最小値を一行で出力せよ．

Sample Input

2 7
4
2
1
0
-1
-2
-4
131
137
2 7
4
2
1
0
-1
-2
-4
131
123
10 7
-4
-2
-1
0
1
2
4
132
134
135
134
132
128
124
122
121
122
5 1
255
0
0
0
0
0
4 1
0
255
0
255
0
0 0

Output for the Sample Input

2
8
0
325125
65026


#include <iostream>
#include <algorithm>
#include <map>
#include <queue>
#include <algorithm>
#include <cstdlib>
#include <map>
using namespace std;

int N;

vector<int> mem;
vector<int> mas;

vector<int> item[25];

int w[16];
int h[16];

char memo[2][1<<25];
char dfs(int init){

	char *a = memo[0] , *b = memo[1];

	for(int j = 0 ; j < (1<<25) ; j++)
		a[j] = 32;

	a[init] = 0;

	for(int i = 0 ; i < 5 * 5 ; i++){
		for(int j = 0 ; j < (1<<25) ; j++) b[j] = a[j];
		for(int j = 0 ; j < (1<<25) ; j++){
			if( a[j] == 32 ) continue;
			for(int k = 0 ; k < item[i].size() ; k++)
				b[j^item[i][k]] = min(b[j^item[i][k]],(char)(a[j]+1));
		}
		swap(a,b);
	}

}

int main(){

	for(int w = 1 ; w <= 5 ; w++){
		for(int h = 1 ; h <= 5 ; h++){
			for(int i = 0 ; i <= 5 - h ; i++){
				for(int j = 0 ; j <= 5 - w ; j++){
					int mask = 0;
					for(int k = 0 ; k < h ; k++)
						for(int l = 0 ; l < w ; l++)
							mask |= (1<<((i+k)*5+j+l));
					//cout << init << " " << mask << endl;
					item[i*5+j].push_back(mask);
				}
			}
		}
	}
	dfs(0);
	while(cin >> N && N){
		int init = 0;
		for(int i = 0 ; i < N ; i++){
			for(int j = 0 ; j < N ; j++){
				int c = 0;
				cin >> c;
				init |= (c<<(i*5+j));
			}
		}
		int x = memo[0][init];
		for(int i = 0 ; i < x ; i++) cout << "myon";
		cout << endl;
	}
}

H: Rectangular Stamps

ICPC で良い成績を収めるには修行が欠かせない．うさぎは ICPC で勝ちたいので，今日も修行をすることにした．

今日の修行は，絵を描くことによって，創造力を高めようというものである．四角いスタンプを用いて，上手く模様を描こう．

大小さまざまなスタンプを使い，4 × 4 のマス目の紙に指定された赤・緑・青の通りの絵を完成させたい．スタンプは長方形であり，マス目にぴったり合わせて使う．スタンプの縦と横を入れ替えることはできない．

紙は最初色が塗られていない状態にある．紙にスタンプを押すと，押された部分がスタンプの色に変わり，下に隠れた色は全く見えなくなる．スタンプの色は付けるインクにより決定されるので，どのスタンプでも，好きな色を選ぶことが可能である．スタンプは紙から一部がはみ出た状態で押すことも可能であり，はみ出た部分は無視される．

1 つのスタンプを複数回使うことは可能である．同じスタンプを別の色に対して使ってもよい．スタンプを押すのはやや神経を使う作業なので，出来るだけスタンプを押す回数を少なくしたい．

Input

N
H1 W1
...
HN WN
C1,1C1,2C1,3C1,4
C2,1C2,2C2,3C2,4
C3,1C3,2C3,3C3,4
C4,1C4,2C4,3C4,4

N はスタンプの個数，Hi, Wi (1 ≤ i ≤ N) はそれぞれ，i 番目のスタンプの縦の長さ，横の長さを表す整数である．Ci, j (1 ≤ i ≤ 4，1 ≤ j ≤ 4) は，上から i 行目，左から j 列目のマスについて指定された絵の色を表す文字である．赤は R ，緑は G ，青は B で表される．

1 ≤ N ≤ 16，1 ≤ Hi ≤ 4，1 ≤ Wi ≤ 4 を満たす．(Hi, Wi) として同一の組は複数回現れない．

Output

絵を完成させるためにスタンプを押さなければならない最小の回数を 1 行に出力せよ．

Sample Input 1

2
4 4
1 1
RRRR
RRGR
RBRR
RRRR

Sample Output 1

3

Sample Input 2

1
2 3
RRGG
BRGG
BRRR
BRRR

Sample Output 2

5


#include <iostream>
#include <string>
#define N1 (1000+1)
using namespace std;
int find(int);
void unite(int,int);
bool same(int,int);
int tree[N1*N1];
string str[N1];
int main(){
  int W,H,N,x,y,findy,findx;
  int dx[4]={0,1,0,-1};
  int dy[4]={-1,0,1,0};
  cin >> W >> H;
  for(int i=0;i<H;i++) cin >> str[i];
  for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      tree[i*W+j]=i*W+j;
    }
  }
  for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      if(str[i][j]=='t') findy=i,findx=j;
      if(str[i][j]!='#'){
	for(int k=0;k<4;k++)
	  if(0<=i+dy[k]&&i+dy[k]<H&&0<=j+dx[k]&&j+dx[k]<W)
	    if(str[i+dy[k]][j+dx[k]]!='#')
	      unite(i*W+j,(i+dy[k])*W+(j+dx[k]));
      }
    }
  }
  cin >> N;
  int flag=0;
  if(same(0,findy*W+findx)){
    flag=1;
    cout << 0 << endl;
  }
  int cnt=0;
  while(N--&&flag==0){
    cnt++;
    cin >> x >> y;
    str[y][x]='.';
    for(int i=0;i<4;i++)
      if(0<=y+dy[i]&&y+dy[i]<H&&0<=x+dx[i]&&x+dx[i]<W&&str[y+dy[i]][x+dx[i]]!='#')
	unite(y*W+x,(y+dy[i])*W+(x+dx[i]));
    if(same(0,findy*W+findx)){
      flag=1;
      cout << cnt << endl;
      break;
    }
  }
  if(flag==0) cout << -1 << endl;
  return 0;
}
int st[N1*N1];
int find(int x){
  int cnt=0;
  while(x!=tree[x]){
    x=tree[x];
    st[cnt]=x;
    cnt++;
  }
  while(cnt>0){
    cnt--;
    tree[st[cnt]]=x;
  }
  return x;
}
void unite(int x,int y){
  x=find(x),y=find(y);
  if(x==y) return ;
  if(x<y) swap(x,y);
  tree[x]=y;
}
bool same(int x,int y){
  if(find(x)==find(y)) return true;
  return false;
}

Lucky Dip

Time Limit: 8 sec / Memory Limit: 64 MB

C: 福袋

福袋，それは年始を祝う商習慣の一つである．
人気の福袋には多くの人が開店前から行列を作り，ターゲットの福袋へダッシュする．
この風物詩に魅了されたあなたは，今年もお目当ての福袋を狙い，計画を立てていた．

しかし，お客を呼び寄せる側の某百貨店の店長は頭を悩ませていた．
どうやらフロアの準備が開店に間に合いそうにない．

そこで店長はある一つのアイディアを思いついた．
それは開店後，店内を徐々に開放すればなんとか営業できるのではないかというものである．

あなたは刻一刻と変化する店内の情報を元に，お目当ての福袋がどの時間帯から入手できるのかを調べたい．

Input

入力は単一のデータセットで与えられ，EOFで終了する．

店内の様子は各行が W 文字からなる H 行の文字列で表される．

1 行目

W H
2 < W, H <= 1000

続く H 行

店内の様子

.: 床

#: 壁

t: 目的の福袋

目的の福袋は店内に必ず1つだけ存在する．

H + 2 行目

営業時間 N (0 <= N <= 1000)

続く N 行

x1 y1
x2 x2
...
xi yi
...
xn yn

(xi, yi)は，i 時間目に開放される壁の座標を表す．(0 <= xi < W, 0 <= yi < H)

xi が列，yi が行である．

開放される壁の座標の位置が "#" なら "." に置き換え，"." なら何もしない．

目的の福袋が開放されることはない．

(0, 0) が壁になることはない．

またあるマスからの移動は，上下左右の4方向のマスへのみが可能であり，壁の上へ移動することはできないものとする．

Output

左上(0, 0) から t の座標へ辿りつけるようになる時間 s (-1 <= s <= N)を1行で出力せよ．

壁を開放せずに辿りつける場合，0 を出力せよ．

営業時間が終了しても到達できなければ -1 を出力すること．

Sample Input 1

10 10
.....#....
.....#....
.....#....
######....
..........
####......
....###...
t..#..####
...##.....
....#...##
3
0 3
0 5
4 6

Sample Output 1

2

Sample Input 2

10 10
.....#....
.....#....
.....#....
##########
##########
##########
##########
t..#..####
...##.....
....#...##
3
0 3
0 5
4 6

Sample Output 2

-1


#define NDEBUG

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <tuple>
#include <cassert>
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <stack>
#include <random>
using namespace std;

inline int fastmax(int a, int b) {
    assert(sizeof(int) == 4);
    return a - ((a-b) & (a-b)>>31);
}
inline void fastswap(int &a, int &b) {
    assert(&a == &b);
    a ^= b;
    b ^= a;
    a ^= b;
}
typedef long long ll;
struct LCNode {
    typedef LCNode* NP;
    typedef int D;
    static const int INF = 1LL<<25;
    static LCNode last_d;
    static NP last;
    NP p, l, r;
    int sz;
    int v, sm, lz;
    int lsm, rsm, ma, mv;
    bool rev, lzf;
    LCNode(D v) :p(NULL), l(last), r(last), sz(1),
        v(v), sm(v), rev(false),
        lsm(max(v, 0)), rsm(max(v, 0)), ma(max(v, 0)), mv(v) {}
    LCNode() : l(NULL), r(NULL), sz(0), v(-INF), mv(-INF) {}
    inline int pos() {
        if (p) {
            if (p->l == this) return -1;
            if (p->r == this) return 1;
        }
        return 0;
    }
    inline void rot() {
        NP qq = p->p;
        int pps = p->pos();
        if (p->l == this) {
            p->l = r; r->p = p;
            r = p; p->p = this;
        } else {
            p->r = l; l->p = p;
            l = p; p->p = this;
        }
        p->update(); update();
        p = qq;
        if (!pps) return;
        if (pps == -1) {
            qq->l = this;
        } else {
            qq->r = this;
        }
        qq->update();
    }
    void splay() {
        assert(this != last);
        int ps;
        while ((ps = pos())) {
            int pps = p->pos();
            if (!pps) {
                rot();
            } else if (ps == pps) {
                p->rot(); rot();
            } else {
                rot(); rot();
            }
        }
    }
    void expose() {
        assert(this != last);
        supush();
        NP u = this;
        do {
            u->splay();
        } while ((u = u->p));
        u = last;
        u->p = this;
        do {
            u->p->r = u;
            u->p->update();
            u = u->p;
        } while (u->p);
        splay();
    }
    void push() {
        int lsz = l->sz, rsz = r->sz;
        if (rev) {
            if (lsz) {
                l->revdata();
            }
            if (rsz) {
                r->revdata();
            }
            rev = false;
        }
        if (lzf) {
            if (lsz) {
                l->lzdata(lz);
            }
            if (rsz) {
                r->lzdata(lz);
            }
            lzf = false;
        }
    }
    const static int SS = 200001;
    static NP st[SS];
    static int stc;
    void supush() {
        NP u = this;
        while (u) {
            st[stc++] = u;
            u = u->p;
        }
        while (stc) {
            st[--stc]->push();
        }
    }
    inline void revdata() {
        swap(l, r);
        fastswap(lsm, rsm);
        rev ^= true;
    }
    inline void lzdata(D d) {
        v = mv = d;
        sm = sz*d;
        lsm = rsm = ma = fastmax(0, sm);
        lz = d;
        lzf = true;
    }
    NP update() {
        assert(this != last);
        sz = 1+l->sz+r->sz;
        sm = v+l->sm+r->sm;
        lsm = fastmax(l->lsm, l->sm+v+r->lsm);
        rsm = fastmax(r->rsm, r->sm+v+l->rsm);
        ma = l->rsm+v+r->lsm;
        ma = fastmax(ma, l->ma);
        ma = fastmax(ma, r->ma);
        mv = v;
        mv = fastmax(mv, l->mv);
        mv = fastmax(mv, r->mv);
        return this;
    }

    void evert() {
        expose();
        revdata();
    }
};
LCNode LCNode::last_d = LCNode();
LCNode::NP LCNode::last = &last_d;
LCNode::NP LCNode::st[LCNode::SS];
int LCNode::stc = 0;

inline int getint() {
    char c;
    int res = 0;
    bool neg = false;
    while (true) {
        c = getchar_unlocked();
        if (c == '-') {
            neg = true;
            break;
        }
        if ('0' <= c && c <= '9') {
            res = c-'0';
            break;
        }
    }
    while (c = getchar_unlocked(), '0' <= c && c <= '9') {
        res *= 10;
        res += c-'0';
    }
    if (neg) res *= -1;
    return res;
}

inline void putint(int d) {
    static char buf[10];
    int c = 0;
    bool neg = false;
    if (d < 0) {
        putchar_unlocked('-');
        d *= -1;
    }
    if (!d) {
        putchar_unlocked('0');
        return;
    }
    while (d) {
        buf[c++] = d%10;
        d = d/10;
    }
    while (c--) {
        putchar_unlocked(buf[c]+'0');
    }
}

const int MN = 200001;
LCNode tr[MN];
int main() {
    int n = getint(), q = getint();
    for (int i = 0; i < n; i++) {
        int w = getint();
        tr[i] = LCNode(w);
    }
    for (int i = 0; i < n-1; i++) {
        int s = getint(), e = getint(); s--; e--;
        tr[s].evert();
        tr[e].expose();
        tr[s].p = tr+e;
    }
    for (int i = 0; i < q; i++) {
        int t = getint(), a = getint(), b = getint(), c = getint();
        a--; b--;
        if (t <= 1) {
            tr[a].evert();
            tr[b].expose();
            tr[b].lzdata(c);
        } else {
            tr[a].evert();
            tr[b].expose();
            int d;
            if (tr[b].mv < 0) d = tr[b].mv;
            else d = tr[b].ma;
            putint(d);
            putchar_unlocked('\n');
        }
    }
}

Do use segment tree

Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries,
process the queries in order and output a value for each output query.
The given tree is connected and each node on the tree has a weight wi (-10,000 ≤ wi ≤ 10,000).

Each query consists of a number ti (ti = 1, 2), which indicates the type of the query , and three numbers ai, bi and ci (1 ≤ ai, bi ≤ n, -10,000 ≤ ci ≤ 10,000).
Depending on the query type, process one of the followings:

(ti = 1: modification query)
Change the weights of all nodes on the shortest path between ai and bi (both inclusive) to ci.

(ti = 2: output query)
First, create a list of weights on the shortest path between ai and bi (both inclusive) in order. After that, output the maximum sum of a non-empty continuous subsequence of the weights on the list. ci is ignored for output queries.

Input

The first line contains two integers n and q.
On the second line, there are n integers which indicate w1, w2, ... , wn.

Each of the following n - 1 lines consists of two integers si and ei (1 ≤ si, ei ≤ n),
which means that there is an edge between si and ei.

Finally the following q lines give the list of queries, each of which contains four integers in the format described above.
Queries must be processed one by one from top to bottom.

Output

For each output query, output the maximum sum in one line.

Sample Input 1

3 4
1 2 3
1 2
2 3
2 1 3 0
1 2 2 -4
2 1 3 0
2 2 2 0

Output for the Sample Input 1

6
3
-4

Sample Input 2

7 5
-8 5 5 5 5 5 5
1 2
2 3
1 4
4 5
1 6
6 7
2 3 7 0
2 5 2 0
2 4 3 0
1 1 1 -1
2 3 7 0

Output for the Sample Input 2

12
10
10
19

Sample Input 3

21 30
10 0 -10 -8 5 -5 -4 -3 1 -2 8 -1 -7 2 7 6 -9 -6 3 4 9
10 3
3 2
3 12
12 4
4 13
4 9
10 21
21 1
1 11
11 14
1 15
10 6
6 17
6 16
6 5
5 18
5 19
10 7
10 8
8 20
1 1 21 -10
1 3 19 10
2 1 13 0
1 4 18 8
1 5 17 -5
2 16 7 0
1 6 16 5
1 7 15 4
2 4 20 0
1 8 14 3
1 9 13 -1
2 9 18 0
1 10 12 2
1 11 11 -8
2 21 15 0
1 12 10 1
1 13 9 7
2 6 14 0
1 14 8 -2
1 15 7 -7
2 10 2 0
1 16 6 -6
1 17 5 9
2 12 17 0
1 18 4 6
1 19 3 -3
2 11 8 0
1 20 2 -4
1 21 1 -9
2 5 19 0

Output for the Sample Input 3

20
9
29
27
10
12
1
18
-2
-3


#include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-6)
#define equals(a,b) (fabs((a)-(b)) < EPS)
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0

using namespace std;

class Point{
public:
  double x,y;

  Point(double x = 0,double y = 0): x(x),y(y){}

  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  Point operator * (Point a){ return Point(x * a.x - y * a.y, x * a.y + y * a.x); }

  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }

  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }

};

struct Segment{
  Point p1,p2;
  Segment(Point p1 = Point(),Point p2 = Point()):p1(p1),p2(p2){}
  bool operator <  (const Segment& s) const { return ( p2 == s.p2 ) ? p1 < s.p1 : p2 < s.p2; }
  bool operator == (const Segment& s) const { return ( s.p1 == p1 && s.p2 == p2 ) || ( s.p1 == p2 && s.p2 == p1 ); }

};

typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;

ostream& operator << (ostream& os,const Point& a){ os << "(" << a.x << "," << a.y << ")"; }

ostream& operator << (ostream& os,const Segment& a){ os << "( " << a.p1 << " , " << a.p2 << " )"; }

double dot(Point a,Point b){ return a.x*b.x + a.y*b.y; }

double cross(Point a,Point b){ return a.x*b.y - a.y*b.x; }

double norm(Point a){ return a.x*a.x+a.y*a.y; }

double abs(Point a){ return sqrt(norm(a)); }

//rad ????§???????????????¢?????§?????????????????¨
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }

// ??????????????¢????????????
double toRad(double agl){ return agl*M_PI/180.0; }

// a => prev, b => cur, c=> next
// prev ?????? cur ????????£??? next ????????????????§????????±???????
double getArg(Point a,Point b,Point c){
  double arg1 = atan2(b.y-a.y,b.x-a.x);
  double arg2 = atan2(c.y-b.y,c.x-b.x);
  double arg = fabs( arg1 - arg2 );
  while( arg > M_PI ) arg -= 2.0 * M_PI;
  return fabs(arg);
}

int ccw(Point p0,Point p1,Point p2){
  Point a = p1-p0;
  Point b = p2-p0;
  if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS)return CLOCKWISE;
  if(dot(a,b) < -EPS)return ONLINE_BACK;
  if(norm(a) < norm(b))return ONLINE_FRONT;
  return ON_SEGMENT;
}

Polygon andrewScan(Polygon s) {
  Polygon u,l;
  if(s.size() < 3)return s;

  sort(s.begin(),s.end());

  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[s.size()-1]);
  l.push_back(s[s.size()-2]);

  for(int i=2;i<s.size();i++) {
      for(int n=u.size();n >= 2 && ccw(u[n-2],u[n-1],s[i]) != CLOCKWISE; n--)
        u.pop_back();
      u.push_back(s[i]);
    }

  for(int i=s.size()-3; i>=0 ; i--) {
      for(int n=l.size(); n >= 2 && ccw(l[n-2],l[n-1],s[i]) != CLOCKWISE; n--)
        l.pop_back();
      l.push_back(s[i]);
    }

  reverse(l.begin(),l.end());

  for(int i = u.size()-2; i >= 1; i--) l.push_back(u[i]);

  return l;
}

inline double heron(Point A,Point B,Point C){
  double a = abs(B-C);
  double b = abs(A-C);
  double c = abs(A-B);
  double s = ( a + b + c ) / 2;
  return sqrt( s * ( s - a ) * ( s - b ) * ( s - c ) );
}

// -----------------------------------------------------------

const int MAX_V = 1510;
int V,nV;
vector<Point> ps,nps;

bool LT(double a,double b) { return !equals(a,b) && a < b; }
bool LTE(double a,double b) { return equals(a,b) || a < b; }

double ternarySearch(int a,int b){
  int L = 1, R = ( a < b ) ? ( ( b - a - 1 + nV ) % nV ) : ( ( a - 1 - b + nV) % nV );
  int sp = a;
  int prev = -1;
  rep(_,120){
    if( LT(heron(nps[((L+R*2)/3+sp)%nV],nps[a],nps[b]),heron(nps[((L*2+R)/3+sp)%nV],nps[a],nps[b])) ) {
      R = ( L + R * 2 ) / 3;
    } else {
      L = ( L * 2 + R ) / 3;
    }
    if( prev == ((int)((L+R)*0.5+sp))%nV ) break;
    prev = (int)((L+R)*0.5+sp)%nV;
  }
  return heron(nps[(int)(((L+R)*0.5)+sp)%nV],nps[a],nps[b]);
}

void compute(){
  nps = andrewScan(ps);
  nV = nps.size();
  double maxi = 0;
  if( nV == 3 ) {
    rep(i,V) {
      if( nps[0] == ps[i] || nps[1] == ps[i] || nps[2] == ps[i] ) continue;
      double area1 = heron(nps[0],nps[1],ps[i]);
      double area2 = heron(nps[1],nps[2],ps[i]);
      double area3 = heron(nps[2],nps[0],ps[i]);
      double area4 = heron(nps[0],nps[1],nps[2]);
      maxi = max(maxi,area4-min(area1,min(area2,area3)));
    }
  } else {
    rep(i,nV) REP(j,i+1,nV) maxi = max(maxi,ternarySearch(i,j)+ternarySearch(j,i));
  }
  printf("%.1f\n",maxi);
}

int main(){
  scanf("%d",&V);
  ps.resize(V);
  rep(i,V) scanf("%lf %lf",&ps[i].x,&ps[i].y);
  compute();
  return 0;
}

Problem H: Magic Walls

You are a magician and have a large farm to grow magical fruits.

One day, you saw a horde of monsters, approaching your farm. They would ruin your magical farm once they reached your farm. Unfortunately, you are not strong enough to fight against those monsters. To protect your farm against them, you decided to build magic walls around your land.

You have four magic orbs to build the walls, namely, the orbs of Aquamarine (A), Bloodstone (B), Citrine (C) and Diamond (D). When you place them correctly and then cast a spell, there will be magic walls between the orbs A and B, between B and C, between C and D, and between D and A. The walls are built on the line segments connecting two orbs, and form a quadrangle as a whole. As the monsters cannot cross the magic walls, the inside of the magic walls is protected.

Nonetheless, you can protect only a part of your land, since there are a couple of restrictions on building the magic walls. There are N hills in your farm, where the orbs can receive rich power of magic. Each orb should be set on the top of one of the hills. Also, to avoid interference between the orbs, you may not place two or more orbs at the same hill.

Now, you want to maximize the area protected by the magic walls. Please figure it out.

Input

The input begins with an integer N (4 ≤ N ≤ 1500), the number of the hills. Then N line follow. Each of them has two integers x (0 ≤ x ≤ 50000) and y (0 ≤ y ≤ 50000), the x- and y-coordinates of the location of a hill.

It is guaranteed that no two hills have the same location and that no three hills lie on a single line.

Output

Output the maximum area you can protect. The output value should be printed with one digit after the decimal point, and should be exact.

Sample Input 1

5
2 0
0 1
1 3
4 2
3 4

Output for the Sample Input 1

7.5

Sample Input 2

4
0 0
0 3
1 1
3 0

Output for the Sample Input 2

3.0


#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cstring>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <utility>
#include <iomanip>
#include <algorithm>
#include <functional>
using namespace std;

typedef long long ll;
typedef vector<int> vint;
typedef vector<ll> vll;
typedef pair<int,int> pint;

#define DE 1
#define FI first
#define SE second
#define PB push_back
#define MP make_pair
#define ALL(s) (s).begin(),(s).end()
#define REP(i,n) for (int i = 0; i < (int)(n); ++i)
#define EACH(i,s) for (typeof((s).begin()) i = (s).begin(); i != (s).end(); ++i)
#define COUT(x) cout<<#x<<" = "<<(x)<<" (L"<<__LINE__<<")"<<endl

template<class T1, class T2> ostream& operator<<(ostream &s, pair<T1,T2> P){return s<<'<'<<P.first<<", "<<P.second<<'>';}
template<class T> ostream& operator<<(ostream &s, vector<T> P) {s<<"{ ";for(int i=0;i<P.size();++i){if(i>0)s<<", ";s<<P[i];}return s<<" }"<<endl;}
template<class T1, class T2> ostream& operator<<(ostream &s, map<T1,T2> P) {s<<"{ ";for(typeof(P.begin()) it=P.begin();it!=P.end();++it){if(it!=P.begin())s<<", ";s<<'<'<<it->first<<"->"<<it->second<<'>';}return s<<" }"<<endl;}

int main() {
    //freopen( "/Users/macuser/Documents/Programming/Contest/input.in", "r", stdin );

    int N;
    cin >> N;
    stack<int> st;
    int res = 0;

    st.push(0);
    for (int i = 0; i < N; ++i) {
        int a; cin >> a;
        if (a > st.top()) st.push(a);
        else if (a == st.top()) {}
        else {
            while (st.top() > a) {
                st.pop();
                ++res;
            }
            if (a > st.top()) st.push(a);
        }
    }
    cout << res + st.size() - 1 << endl;

    return 0;
}

D - カーペット

総合研究7号館の引越しに伴い，研究室にカーペットを敷くことになった．
この問題では研究室を上から見たときの床を，二次元平面上の多角形とみなす．
床の形状を表す要素数Nの数列\{a_i\}が与えられる．
R_iを，左下の座標が(i,0)で右上の座標が(i+1,a_i)である各辺がx軸またはy軸に平行な長方形の境界及び内部領域とする．
このとき，床を表す多角形はR_1 ∪ R_2 ∪ R_3 ∪ … ∪ R_Nによって表される．

カーペットは長方形であればどんな大きさのものを何枚でも用意することができる．
以下の条件を満たすようにカーペットを配置し，研究室の床を全て覆いつくしたい．

カーペットは研究室からはみ出してはいけない．

カーペットはいくらでも重ねて敷くことが可能である．このとき，カーペットの厚さは無視する．

カーペットを切り離して利用することはできない．

カーペットは各辺がx軸またはy軸に平行になるように配置しなければならない．

研究室の床を覆い尽くすために必要なカーペットの最小数を求めよ．

図D-1. 入力例1の床

図D-2. 入力例2の床

入力形式

入力は以下の形式で与えられる．

N
a_1 … a_N

出力形式

研究室の床を覆い尽くすために必要なカーペットの最小数を１行に出力せよ．

制約

1 \leq N \leq 2 \times 10^5

1 \leq a_i \leq 10^9

入力値はすべて整数である．

入出力例

入力例1

3
1 2 1

出力例1

2

入力例2

10
1 2 2 1 3 4 3 1 2 2

出力例2

5