Problem:
F : 卵 / Eggs
問題文
1
か月前のことである． 小学生の肉西君は夏休みの宿題をやっていなかった． そこで自由研究は家にあった卵の強度を調べることにした．
この研究において，卵を高さ
H
から落としても割れず， 高さ
H+1
から落とすと割れるとき， その卵の強度は
H
であると定義する． ここで
H
は非負整数であり，非負整数以外の高さから落とすことは無いとする． 肉西くんは卵を
1
つ落下させる実験を行う． 実験の結果は割れるか割れないかのいずれかである． また，卵の強度は全て同じである．つまり，どの卵を用いても実験の結果は同じである．
肉西くんは高さ
1
から
N
までの整数の高さの段からなる階段と， 強度が不明な
E
個の卵を用意した． 高さ
0
では割れず，高さ
N+1
では割れるということは既にわかっている． 肉西くんは各段と同じ高さから地面に向かって落とし，その度に卵が割れたか割れなかったかを調べる． このとき割れた卵は二度と使えないが，割れなかった場合は再利用できる． この実験を卵が残っている限り続けることができる． 何度か実験を繰り返し，上に定めた
H
が求まったとき，卵の強度が求まったとする．
夏休み終了まで後数日しか無い． 最小の回数で実験を終わらせないと間に合わない． そこで，肉西くんの兄であるあなたは，卵の強度を知るために 落とす回数が少なくなるように最適な方法をとった場合に 必要な実験回数の最大値を求めるプログラムを書くことにした．
入力
T
N_1 E_1
…
N_T
E_T
1 つのファイルに複数のテストケースが含まれる．
1
行目に整数
T
が与えられる．
1+i
行目に
i
番目のテストケース
E_i, N_i
が与えられる
制約
整数である
1 ≤ T ≤ 1000
1 ≤ N_i ≤ 10^{18}
1 ≤ E_i ≤ 50
出力が
50
を超えるような入力は含まれない
出力
i
番目のテストケースに対する答えを
i
行目に出力せよ． 全体で
T
行にわたる．
サンプル
サンプル入力1
3
5 1
5 2
1 2
サンプル出力1
5
3
1
1
つ目の場合
卵が
1
つしかないため
1
段目から順に落としていくしかない
2
つ目の場合
まず
2
段目から落とす
2
段目から落として割れた場合
1
段目から落とす
2
段目から落として割れなかった場合
4
段目から落とす
1
段目から落として割れた場合実験終了
1
段目から落として割れなかった場合実験終了
4
段目から落として割れた場合
3
段目から落とす
4
段目から落として割れなかった場合
5
段目から落とす
3
段目から落として割れた場合実験終了
3
段目から落として割れなかった場合実験終了
5
段目から落として割れた場合実験終了
5
段目から落として割れなかった場合実験終了
3
つ目の場合
1
段目から落として実験終了

Submitted solutions:

code_snippet: #include <iostream>
#include <algorithm>
using namespace std;

long long Q, dp[60][200009], A[2000009];

void init() {
	for (int i = 1; i <= 2000000; i++) {
		long long V1 = A[i - 1] + 1;
		long long V2 = 1LL * i * (i - 1) / 2LL + 1;
		A[i] = V1 + V2 - 1; if (A[i] >= (1LL << 61)) A[i] = (1LL << 61);
	}
	for (int i = 1; i <= 200000; i++) {
		long long V1 = dp[4][i - 1] + 1;
		long long V2 = A[i - 1] + 1;
		dp[4][i] = V1 + V2 - 1; if (dp[4][i] >= (1LL << 61)) dp[4][i] = (1LL << 61);
	}
	for (int i = 5; i < 60; i++) {
		for (int j = 1; j < 200000; j++) {
			long long V1 = dp[i][j - 1] + 1;
			long long V2 = dp[i - 1][j - 1] + 1;
			dp[i][j] = V1 + V2 - 1; if (dp[i][j] >= (1LL << 61)) dp[i][j] = (1LL << 61);
		}
	}
}

long long score(long long x, long long y) {
	// x 個の卵で y 回の操作
	if (x == 1) return y;
	if (x == 2) {
		if (y >= 2000000000) return (1LL << 61);
		return y * (y + 1) / 2;
	}
	if (x == 3) {
		if (y >= 2000000) return (1LL << 61);
		return A[y];
	}
	if (y >= 200000) return (1LL << 61);
	return dp[x][y];
}

int main() {
	cin >> Q; init();
	for (int i = 1; i <= Q; i++) {
		long long N, E; cin >> N >> E;
		
		long long L = 1, R = (1LL << 60), M, minx = (1LL << 60);
		for (int j = 1; j <= 80; j++) {
			M = (L + R) / 2;
			if (score(E, M) >= N) { R = M; minx = min(minx, M); }
			else L = M;
		}
		cout << minx << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 106236
final_rank: 3

code_snippet: #include <cstdio>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <bitset>
#include <numeric>
#include <limits>
#include <climits>
#include <cfloat>
#include <functional>
using namespace std;

const long long INF = LLONG_MAX / 2;

int main()
{
    int t;
    cin >> t;

    while(--t >= 0){
        long long n;
        int e;
        cin >> n >> e;

        vector<vector<long long> > dp(51, vector<long long>(e+1, 0));
        for(int i=1; i<=50; ++i){
            for(int j=1; j<=e; ++j){
                dp[i][j] = dp[i-1][j] + dp[i-1][j-1] + 1;
                dp[i][j] = min(dp[i][j], INF);
            }
        }

        int ans = 0;
        while(dp[ans][e] < n)
            ++ ans;
        cout << ans << endl;
    }

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1248
final_rank: 1

code_snippet: #include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <set>
#include <map>
#include <queue>
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cctype>
#include <cassert>
#include <limits>
#include <functional>
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
#if defined(_MSC_VER) || __cplusplus > 199711L
#define aut(r,v) auto r = (v)
#else
#define aut(r,v) __typeof(v) r = (v)
#endif
#define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)
#define all(o) (o).begin(), (o).end()
#define pb(x) push_back(x)
#define mp(x,y) make_pair((x),(y))
#define mset(m,v) memset(m,v,sizeof(m))
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
using namespace std;
typedef vector<int> vi; typedef pair<int,int> pii; typedef vector<pair<int,int> > vpii; typedef long long ll;
template<typename T, typename U> inline void amin(T &x, U y) { if(y < x) x = y; }
template<typename T, typename U> inline void amax(T &x, U y) { if(x < y) x = y; }


template<typename T>T gcd(T x, T y){if(y==0)return x;else return gcd(y,x%y);}

long long nCr_saturated(long long n, long long k) {
	if(k > n) return 0;
	if(k > n / 2) k = n - k;
	if(k == 0) return 1;
	long long r = 1;
	for(int j = 1; j <= k; j ++) {
		ll a = n - k + j; int b = j;
		{	int g = gcd((int)((n - k) % j), j);
			a /= g, b /= g;
		}
		r /= b;
		if(r * 1. * a > 2e18)
			return (long long)1e18 + 1;
		r *= a;
	}
	return min(r, (long long)1e18 + 1);
}

long long solve(long long k, long long n) {
	if(k == 1) return n - 1;
	if(n == 1) return 0;
	int r = 0, i = 0; long long x = n - 1;
	while(true) {
		long long t = 0;
		for(int j = 0; j < k && j <= r; j ++) {
			t += nCr_saturated(r, j);
			if(t >= x) break;
		}
		if(t >= x) break;
		x -= t;
		++ r;
	}
	return r + 1;
}

int main() {
//	rer(n, 0, 100) rer(k, 0, n)
//		cerr << n << ", " << k << ": " << nCr_saturated(n, k) << endl;
	int T;
	scanf("%d", &T);
	rep(ii, T) {
		long long N, E;
		scanf("%lld%lld", &N, &E);
		long long ans = solve(E, N + 1);
		printf("%lld\n", ans);
	}
	return 0;
}
accuracy: 1
time_ms: 360
memory_kb: 1192
final_rank: 2