utsubo’s blog

競技プログラミングとか.

AtCoder Beginner Contest #008 D- 金塊ゲーム

感想

AtCoder Beginner Contest 008 解説
解説スライドを見ながら解きました。

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

int w,h;
vector<int> x,y;
map<tuple<int,int,int,int>,int> memo;

int dfs(int l,int r,int u,int d){
	int res = 0;
	//枠内に回収機があるか
	bool f = false;
	tuple<int,int,int,int> tp = make_tuple(l,r,u,d);
	if(memo.count(tp) != 0)return memo[tp];

	for(int i=0;i<x.size();i++){
		int ret = 0;
		//枠内に回収機がある
		if(l <= x[i] && x[i] <= r && u <= y[i] && y[i] <= d){
			//回収機が枠の端以外にある時は、次の範囲を探索
			if(x[i] != l){
				if(y[i] != u)
					ret += dfs(l,x[i]-1,u,y[i]-1);
				if(y[i] != d)
					ret += dfs(l,x[i]-1,y[i]+1,d);
			}
			if(x[i] != r){
				if(y[i] != u)
					ret += dfs(x[i]+1,r,u,y[i]-1);
				if(y[i] != d)
					ret += dfs(x[i]+1,r,y[i]+1,d);
			}
			f = true;
		}
		res = max(res,ret);
	}
	//枠内に1個も回収機がない
	if(!f)return 0;
	//回収機があれば、(幅+高さ-1)個の金塊が回収できる
	return memo[tp] = res + (r-l+1)+(d-u+1)-1;
}

int main(void) {
	cin >> w >> h;
	int n;
	cin >> n;
	x.resize(n);y.resize(n);
	for(int i=0;i<n;i++){
		cin >> x[i] >> y[i];
	}
	cout << dfs(1,w,1,h) << endl;
	return 0;
}

当時は解説スライド見ても解けなかったし成長を僅かながら感じられた。

yukicoder No.164 ちっちゃくないよ!!

感想

それぞれ、(含まれている数字の最大値+1)進数で最小。
str.to_i(n)で文字列をn進数にできてruby凄い。

n = gets.to_i
a = []
for i in 1..n
	a.push(gets.to_s)
end

t = 0
dic = {}
for s in "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars
	dic[s] = t
	t += 1
end

ar = []
for i in 0..n-1
	ar.push(a[i].to_i(dic[a[i].chars.max]+1))
end
puts ar.min

C++で書くのは辛そうだったので、久々にRubyで書いたけど全く覚えてなくて結局辛かった。

yukicoder No.163 cAPSlOCK

問題

文字列の小文字は大文字に大文字は小文字にする。

感想

それぞれのxor 32をとると大文字・小文字が反対になる。

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

int main(void) {
	string s;
	cin >> s;
	for(int i=0;i<s.size();i++){
		s[i] = s[i]^32;
	}
	cout << s << endl;
	return 0;
}

Twitterで見た

yukicoder No.67 よくある棒を切る問題(1)

感想

長さを二分探索したけど、 EPS=1e-10で回すと大きい数の時、無限ループしてしまいました。
 \log_2 (1e10) = 33.21...なので適当に100回ぐらいで打ち切った。

#include <bits/stdc++.h>

using namespace std;

typedef pair<int,int> P;
typedef pair<int,pair<int,int>> PP;
typedef long long ll;

const double EPS = 1e-10;
const int INF = 1e9;
const int MOD = 1e9+7;

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

struct edge{int to,cost,tm;};

bool func(double len,ll K,vector<int>&L){
	ll cnt = 0;
	for(int i=0;i<L.size();i++){
		cnt += L[i]/len;
		if(cnt >= K)return true;
	}
	return false;
}

int main(void) {
	ll N,K;
	cin >> N;
	vector<int> L(N);
	for(int i=0;i<N;i++){
		cin >> L[i];
	}
	cin >> K;

	double low=0,hi=1e9,mid=0;
	int t = 0;
	while(hi > low+EPS && t < 100){
		mid = (low + hi)/2;
		if(func(mid,K,L)){
			low = mid;
		}else{
			hi = mid;
		}
		t++;
	}
	cout << fixed << setprecision(11) << low << endl;
	return 0;
}

double値の二分探索初めてした気がする。
無限ループに陥らないように気をつけていきたいです。

yukicoder No.27 板の準備

感想

制約が小さいので全探索できそう。
A,B,Cのそれぞれの長さ、それぞれの使う枚数について回して30^6ぐらいだけど実際はもう少し小さいから間に合った。

#include <bits/stdc++.h>

using namespace std;

typedef pair<int,int> P;
typedef pair<int,pair<int,int>> PP;
typedef long long ll;

const double EPS = 1e-8;
const int INF = 1e9;
const int MOD = 1e9+7;

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

int sub(int a,int b,int c,int n){
	int ret = INF/2;
	for(int i=n/c;i>=0;i--){
		for(int j=n/b;j>=0;j--){
			for(int k=n/a;k>=0;k--){
				if(c*i+b*j+a*k == n){
					ret = min(ret,i+j+k);
				}
			}
		}
	}
	return ret;
}
int func(int a,int b,int c,vector<int>& v){
	int ret = 0;
	for(int l=0;l<4;l++){
		ret += sub(a,b,c,v[l]);
	}
	return ret;
}

int main(void) {
	vector<int> v(4);
	cin >> v[0] >> v[1] >> v[2] >> v[3];
	sort(begin(v),end(v));

	int ret = INF;
	for(int a=1;a<=30;a++){
		for(int b=a+1;b<=30;b++){
			for(int c=b+1;c<=30;c++){
				ret = min(ret,func(a,b,c,v));
			}
		}
	}
	cout << ret << endl;
	return 0;
}

★3なのに全探索で通ってしまい不安。
DPで縮められるらしいので調べておきたい。

Codeforces #294(Div.2)

1575->1516(-59)
レートは下がっちゃったけど人が多いのは楽しいですね。


A,B:手間取った。
C:よくわからないので二分探索しようとしたけど、二分探索が書けなくて焦った。
D:累積和してどうするんだろう・・・
E:読めてない


二分探索きっちり書くの難しい。

int low=min,hi=max,mid=0;
while(hi > low+1){
	mid = (low + hi)/2;
	if(/*条件*/){
		low = mid;
	}else{
		hi = mid;
	}
}
cout << low << endl;