【AtCoder】AtCoder Grand Contest 045

比賽鏈接

點擊打開鏈接

官方題解

點擊打開鏈接

Problem A. Xor Battle

考慮維護使得最後一個玩家獲勝的數字集合 SS ,初始時, S={0}S=\{0\}

考慮最後一個回合 ii
若該回合是 0 號玩家的回合,則有 S={xxS}{xAixS}S'=\{x\mid x\in S\}\cup\{x\oplus A_i\mid x\in S\}
若該回合是 1 號玩家的回合,則若 AiSA_i\in S ,則 S=SS'=S ,否則, S=S'=\varnothing

這是因爲 SS 是一個包含 00 的線性空間,因此若 AiSA_i\notin S ,則對於所有 xSx\in S ,有 xAiSx\oplus A_i\notin S
那麼,維護 SS 的線性基,支持插入和詢問某個元素是否在 SS 中即可。

時間複雜度 O(TNLogV)O(TNLogV)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 205;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
ll a[MAXN], b[MAXN], bit[MAXN];
char s[MAXN];
void ins(ll x) {
	for (int i = 60; i >= 0; i--)
		if (x & bit[i]) {
			if (b[i] == 0) {
				b[i] = x;
				break;
			}
			x ^= b[i];
		}
}
bool query(ll x) {
	for (int i = 60; i >= 0; i--)
		if (x & bit[i]) x ^= b[i];
	return x == 0;
}
int main() {
	int T; read(T);
	while (T--) {
		int n; read(n);
		for (int i = 1; i <= n; i++)
			read(a[i]);
		scanf("\n%s", s + 1);
		for (int i = 0; i <= 60; i++)
			b[i] = 0, bit[i] = 1ll << i;
		bool win = false;
		for (int i = n; i >= 1; i--) {
			if (s[i] == '0') ins(a[i]);
			else win |= !query(a[i]);
		}
		if (win) puts("1");
		else puts("0");
	}
	return 0;
}

Problem B. 01 Unbalanced

考慮將 0 看做 1-1 ,將 1 看做 +1+1 ,求出各個位置的前綴和 Si  (0iN)S_i\;(0\leq i\leq N)
可以發現,問題要求我們最小化 SiS_i 集合的極差。

考慮枚舉 SiS_i 集合的最小值 MinMin ,保證 SiS_iMin\geq Min 的情況 下最小化最大值 MaxMax
則應當首先將所有的 ? 替換爲 1 ,若此時,仍然存在 Si<MinS_i<Min ,則顯然不存在合法解。
否則,可以發現從前到後貪心地決定是否將一個 ? 修改爲的 1 變成 0 是最優的。
則可以通過預處理 SiS_i 後綴最小值的方式 O(N)O(N) 解決該問題。

SiS_i 集合最小值的最大值爲 MM ,枚舉 Min=M,M1,M2,Min=M,M-1,M-2,\dots 可以得到一個 O(N2)O(N^2) 的做法。觀察貪心的過程,可以發現 Min=x2Min=x-2 的解不會優於 Min=xMin=x 的解,從而可以只枚舉 Min=M,M1Min=M,M-1 ,降低時間複雜度。

時間複雜度 O(N)O(N)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
char s[MAXN];
int n, a[MAXN], sMin[MAXN]; bool b[MAXN];
void init() {
	for (int i = 1; i <= n; i++) {
		if (s[i] == '0') a[i] = a[i - 1] - 1;
		else a[i] = a[i - 1] + 1;
		if (s[i] == '?') b[i] = true;
	}
	sMin[n + 1] = n + 5;
	for (int i = n; i >= 0; i--)
		sMin[i] = min(sMin[i + 1], a[i]);
}
int work(int limit) {
	int mns = 0;
	for (int i = 1; i <= n; i++) {
		if (s[i] == '?' && sMin[i] - mns - 2 >= limit) {
			b[i] = false;
			mns += 2;
		} 
		a[i] -= mns;
	}
	int Max = 0;
	for (int i = 1; i <= n; i++)
		chkmax(Max, a[i]);
	return Max - limit;
}
int main() {
	scanf("%s", s + 1);
	n = strlen(s + 1);
	int ans = n + 5, tmp = 0;
	init(); chkmin(ans, work(sMin[0]));
	init(); chkmin(ans, work(sMin[0] - 1));
	cout << ans << endl;
	return 0;
}

Problem C. Range Set

首先,我們顯然可以將整個序列染成 1 ,因此,不妨令 ABA\leq B

考慮一個結果序列 SS ,判斷其是否可以到達。
對於一個長度至少爲 AA 的全 0 區間,我們可以將其任意染成一種顏色。
對於一個長度至少爲 BB 的全 1 區間,我們可以將其任意染成一種顏色。

由此,若將長度至少爲 AA 的全 0 區間全部染成 1 後,存在長度至少爲 BB 的全 1 區間,則結果序列 SS 可以被達到。反之,不難證明,結果序列 SS 不能被達到。

那麼,記 dpi,jdp_{i,j} 表示長度爲 ii 的區間,結尾處極長的全 1 區間的長度爲 jj ,轉移時枚舉下一個 1 的位置,可以得到一個 O(N3)O(N^3) 的做法。
觀察轉移形式,用部分和優化即可。

時間複雜度 O(N2)O(N^2)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5005;
const int P = 1e9 + 7;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
int n, a, b, dp[MAXN][MAXN], two[MAXN];
int pd[MAXN][MAXN], aux[MAXN];
void update(int &x, int y) {
	x += y;
	if (x >= P) x -= P;
}
int main() {
	read(n), read(a), read(b);
	if (a < b) swap(a, b); two[0] = 1;
	for (int i = 1; i <= n; i++)
		two[i] = 2ll * two[i - 1] % P;
	dp[0][0] = 1;
	for (int i = 0; i <= n; i++) {
		if (i != 0) update(aux[i], aux[i - 1]);
		update(dp[i][1], aux[i]);
		for (int j = 1; j <= a; j++) {
			update(dp[i][j], pd[i][j]);
			update(pd[i + 1][min(j + 1, a)], pd[i][j]);
		}
		if (i == n) break;
		for (int j = 0; j <= a - 1; j++) {
			update(dp[i + 1][j + 1], dp[i][j]);
			
			update(aux[i + 2], dp[i][j]);
			if (i + b + 1 <= n) update(aux[i + b + 1], P - dp[i][j]);
			
			if (i + b + 1 <= n) update(pd[i + b + 1][min(j + b + 1, a)], dp[i][j]);
			
			if (n - i >= b) update(dp[n][min(j + n - i, a)], dp[i][j]);
		}
	}
	int ans = 0;
	for (int i = 1; i <= n; i++)
		update(ans, 1ll * dp[i][a] * two[n - i] % P);
	cout << ans << endl;
	return 0;
}

Problem D. Lamps and Buttons

考慮 Snuke 的最優策略,應當爲:
隨機操作一盞亮着的燈 xx
px=xp_x=x ,則 xx 永遠不會再次亮起,遊戲結束, Snuke 失敗。
pxxp_x\ne x ,則若 pxp_x 暗了下去,則可以再次操作 xx ,使其亮起;若 pxp_x 亮了起來, Snuke 可以轉而操作 pxp_x ,直至將 xx 所在的置換環全部點亮。

由於排列 pp 的隨機性,我們可以認爲 Snuke 每次隨機都會操作最小的尚未操作的燈。

那麼,一個排列合法當且僅當其滿足如下條件:
tt 表示最小的,使得 pt=t,tAp_t=t,t\leq A 的位置,若不存在,則令 t=A+1t=A+1
對於所有 A+1xNA+1\leq x\leq Nxx 所在的置換環上存在一個 t1\leq t-1 的元素。

考慮如何計數,由於 NN 較大,不妨考慮將置換環中 A+1\geq A+1 的元素刪去,考慮剩餘的置換。
此時,在 tt 之前,可能會有其他的滿足 px=xp_x=x 的自環,但在插入 A+1\geq A+1 的元素後,這些自環將會被補足爲一個至少二元的環。在枚舉 tt 後,我們需要知道兩點:
(1)(1) 、滿足所在置換環中存在 t1\leq t-1 的元素的位置個數 ii
(2)(2) 、滿足 t1\leq t-1 ,且 pt=tp_t=t 的位置個數 jj

考慮將 A+1\geq A+1 的元素插入進置換的合法方案數,應當爲
(NA)j×(i+(NAj)1)NAj(N-A)^{\underline{j}}\times (i+(N-A-j)-1)^{\underline{N-A-j}}

同時,對於所在置換環中不存在 t\leq t 的元素的 max{0,Ni1}\max\{0,N-i-1\} 個位置,其置換的形式是任意的,即有係數
max{0,Ni1}!\max\{0,N-i-1\}!

由此,我們可以設計動態規劃,將上文的 i,ji,j 計入狀態。
轉移時枚舉最小的元素所在的置換環的大小,不難得到一個 O(A3+N)O(A^3+N) 的解法。

觀察轉移,用部分和優化,時間複雜度降爲 O(A2+N)O(A^2+N)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e7 + 5;
const int MAXM = 5e3 + 5;
const int P = 1e9 + 7;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
int fac[MAXN], inv[MAXN];
int power(int x, int y) {
	if (y == 0) return 1;
	int tmp = power(x, y / 2);
	if (y % 2 == 0) return 1ll * tmp * tmp % P;
	else return 1ll * tmp * tmp % P * x % P;
}
int binom(int x, int y) {
	if (y > x) return 0;
	else return 1ll * fac[x] * inv[y] % P * inv[x - y] % P;
}
void update(int &x, int y) {
	x += y;
	if (x >= P) x -= P;
}
void init(int n) {
	fac[0] = 1;
	for (int i = 1; i <= n; i++)
		fac[i] = 1ll * fac[i - 1] * i % P;
	inv[n] = power(fac[n], P - 2);
	for (int i = n - 1; i >= 0; i--)
		inv[i] = inv[i + 1] * (i + 1ll) % P;
}
int n, m, dp[MAXM][MAXM], sum[MAXM][MAXM];
int func(int x, int y) {
	return 1ll * fac[x] * inv[x - y] % P;
}
int main() {
	read(n), read(m), init(n);
	dp[0][0] = 1, sum[0][0] = fac[m - 1];
	for (int i = 1; i <= m; i++)
	for (int j = 0; j <= i; j++) {
		update(dp[i][j], dp[i - 1][j - 1]);
		if (i >= 2) update(dp[i][j], 1ll * sum[i - 2][j] * inv[m - i] % P);
		sum[i][j] = (sum[i - 1][j] + 1ll * dp[i][j] * fac[m - i - 1]) % P;
	}
	int ans = 0;
	for (int i = 0; i <= m; i++)
	for (int j = 0; j <= i && j <= n - m; j++)
		update(ans, 1ll * dp[i][j] * fac[max(m - i - 1, 0)] % P * func(n - m, j) % P * func(i + (n - m - j) - 1, n - m - j) % P);
	cout << ans << endl;
	return 0;
}

Problem E. Fragile Balls

PP 表示滿足 AiBiA_i\ne B_i 的球數。

考慮 Ci=1C_i=1 的情況,此時,答案或是 PP ,或是 1-1

考慮對於每個球,建邊 AiBiA_i\rightarrow B_i ,由題目條件,各個點的入度均不爲 00
定義連通塊爲將有向邊看做無向邊後,形成的連通塊,則可以將連通塊分爲如下三類:
(1)(1) 、連通塊中僅包含一個點,和一條指向自己的邊
(2)(2) 、連通塊中僅包含一個長度 2\geq 2 的環,且不存在其它的邊
(3)(3) 、連通塊中的邊數多於點數

可以發現,若存在第 (2)(2) 類連通塊,答案顯然爲 1-1
同時,若不存在第 (2)(2) 類連通塊,由各個點的入度均不爲 00 的性質,我們可以按照拓撲序構造一組合法的方案。從而,答案爲 PP 當且僅當不存在第 (2)(2) 類連通塊。

考慮原有的問題,在 Ci1C_i\geq 1 的情況下,即使存在第 (2)(2) 類連通塊,也可能有解。

我們可以將一個連通塊外的球 xx 移入第 (2)(2) 類連通塊,從而處理該連通塊。
那麼,記第 (2)(2) 類連通塊的個數爲 XX ,我們必然需要額外花費 XX 步。

考慮球 xx 的如下幾種情況:
(1)(1)xx 在第 (1)(1) 類連通塊內,此時,若要將 xx 移出,必須將另一個球移入 xx 所在的位置,即將 xx 所在的連通塊看做第 (2)(2) 類連通塊處理。這會導致 XX 增加 11 ,同時,我們也可以處理掉 Cx1C_x-1 個連通塊,總的效果是導致 XX 減去 Cx2C_x-2 ,並且額外花費 22 步。
(2)(2)xx 在第 (2)(2) 類連通塊內,我們可以在所在連通塊被處理時將 xx 移出,處理其餘連通塊,並在 xx 移回時繼續處理該連通塊。總的效果是導致 XX 減去 Cx1C_x-1 ,沒有額外花費步數。
(3)(3)xx 在第 (3)(3) 類連通塊內, Ax=BxA_x=B_x ,效果是導致 XX 減去 Cx1C_x-1 ,並且額外花費 11 步。
(4)(4)xx 在第 (3)(3) 類連通塊內, AxBxA_x\ne B_x ,效果是導致 XX 減去 Cx1C_x-1 ,沒有額外花費步數。

同時,由於第 (1),(2)(1),(2) 類連通塊中的元素初始時是不能動的,若 X0X\ne 0 ,必須存在至少一個屬於情況 (3),(4)(3),(4) 的球 xx 。剩餘的問題就變爲了:給定若干個代價 2\leq 2 的物品,求出使得物品總價值 X\geq X 的最小代價。排序後枚舉代價爲 11 的物品個數,用雙指針計算答案即可。

時間複雜度 O(MLogM)O(MLogM)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const int INF  = 1e9 + 7;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
vector <int> res[3];
bool cycle[MAXN]; int x[MAXN], y[MAXN], c[MAXN];
int n, m, ind[MAXN], oud[MAXN], f[MAXN], s[MAXN];
int find(int x) {
	if (f[x] == x) return x;
	else return f[x] = find(f[x]);
}
void merge(int x, int y) {
	x = find(x), y = find(y);
	if (x != y) {
		f[y] = x;
		cycle[y] = false;
		s[x] += s[y];
	}
}
bool cmp(int x, int y) {
	return x > y;
}
int work(ll cnt, bool mode) {
	sort(res[0].begin(), res[0].end(), cmp);
	sort(res[1].begin(), res[1].end(), cmp);
	sort(res[2].begin(), res[2].end(), cmp);
	for (auto x : res[0]) cnt -= x;
	int ans = INF;
	if (mode == false) {
		if (res[1].empty()) return INF;
		cnt -= res[1][0];
		res[1].erase(res[1].begin());
		int cur = res[2].size(); ll sum = 0;
		for (auto x : res[2]) sum += x;
		while (cur >= 1 && sum - res[2][cur - 1] >= cnt)
			sum -= res[2][--cur];
		if (sum >= cnt) chkmin(ans, 1 + cur * 2);
		for (int i = 0; i < res[1].size(); i++) {
			cnt -= res[1][i];
			while (cur >= 1 && sum - res[2][cur - 1] >= cnt)
				sum -= res[2][--cur];
			if (sum >= cnt) chkmin(ans, 1 + (i + 1) + cur * 2);
		}
		return ans;
	} else {
		if (cnt <= 0) return 0;
		int cur = res[2].size(); ll sum = 0;
		for (auto x : res[2]) sum += x;
		while (cur >= 1 && sum - res[2][cur - 1] >= cnt)
			sum -= res[2][--cur];
		if (sum >= cnt) chkmin(ans, cur * 2);
		for (int i = 0; i < res[1].size(); i++) {
			cnt -= res[1][i];
			while (cur >= 1 && sum - res[2][cur - 1] >= cnt)
				sum -= res[2][--cur];
			if (sum >= cnt) chkmin(ans, (i + 1) + cur * 2);
		}
		return ans;
	}
}
int main() {
	read(n), read(m);
	for (int i = 1; i <= n; i++)
		f[i] = i, s[i] = 1, cycle[i] = true;
	for (int i = 1; i <= m; i++) {
		read(x[i]), read(y[i]), read(c[i]);
		merge(x[i], y[i]), oud[x[i]]++, ind[y[i]]++;
	}
	for (int i = 1; i <= n; i++)
		if (ind[i] != 1 || oud[i] != 1) cycle[find(i)] = false;
	int cnt = 0, ans = 0;
	for (int i = 1; i <= n; i++)
		if (f[i] == i) cnt += cycle[i] && s[i] >= 2;
	ll lft = cnt; bool key = false;
	for (int i = 1; i <= m; i++) {
		ans += x[i] != y[i];
		if (c[i] >= 2) {
			if (cycle[find(x[i])]) {
				if (s[find(x[i])] == 1) res[2].push_back(c[i] - 2);
				else res[0].push_back(c[i] - 1);
			} else {
				if (x[i] == y[i]) res[1].push_back(c[i] - 1);
				else {
					lft -= c[i] - 1;
					key = true;
				}
			}
		}
	}
	if (cnt == 0) {
		cout << ans << endl;
		return 0;
	} else {
		int tmp = work(lft, key);
		if (tmp == INF) cout << -1 << endl;
		else cout << ans + cnt + tmp << endl;
	}
	return 0;
}

Problem F. Division into Multiples

G=(A,B)1G=(A,B)\ne 1 ,則可以令 A=AG,B=BG,C=C(G,C)A=\frac{A}{G},B=\frac{B}{G},C=\frac{C}{(G,C)} ,從而 (A,B)=1(A,B)=1 ;
G=(A,C)1G=(A,C)\ne 1 ,則可以令 A=AG,C=CG,Y=YGA=\frac{A}{G},C=\frac{C}{G},Y=\lfloor\frac{Y}{G}\rfloor ,從而 (A,C)=1(A,C)=1
G=(B,C)1G=(B,C)\ne 1 ,則可以令 B=BG,C=CG,X=XGB=\frac{B}{G},C=\frac{C}{G},X=\lfloor\frac{X}{G}\rfloor ,從而 (B,C)=1(B,C)=1
ACA\geq CBCB\geq C ,則可以令 A=A%C,B=B%CA=A\%C,B=B\%C

由此,問題轉化爲了 (A,B)=(A,C)=(B,C)=1(A,B)=(A,C)=(B,C)=1 的情況。
考慮方程 Ax+By0  (mod  C)Ax+By\equiv 0\;(mod\;C) ,令 D=A×B1D=A\times B^{-1} ,其中 B1B^{-1} 表示 BB 在模 CC 意義下的乘法逆元。則有通解:
{xkyk×D\left\{\begin{array}{rcl}x\equiv k\\y\equiv -k\times D\end{array} \right.

注意到若存在兩組解 (x0,y0),(x1,y1)(x_0,y_0),(x_1,y_1) 滿足 x0x1,y0y1x_0\leq x_1,y_0\leq y_1 ,則 (x1,y1)(x_1,y_1) 是不優的,我們不會使用。考慮求出在這個意義下,我們可能使用的那些解。

考慮如下子問題:給定 C×DC\times D 的平面,從原點處出發,一束光線沿第一象限角平分線方向發射,達到 x=Cx=C 時,令 x=0x=0 ,達到 y=Dy=D 時,令 y=0y=0 。我們希望求出 y=Dy=D 上被光束擊中時是前綴最大值的點。

考慮一個 D×DD\times D 的正方形,可以發現,光束從任意點射入,都將從其對面的點射出,從而可以刪去一個極大的,包含原點的正方形。利用類似歐幾里得算法的過程重複刪去正方形,我們可以得到所求的所有可能使用的解。它們在平面上形成了 O(LogV)O(LogV) 段線段。

進一步思考上述算法的過程,我們還可以發現,這些解構成了一個下凸殼。
我們現在想要選擇若干個向量,滿足求和後,兩維均小於等於 (X,Y)(X,Y)

由解集的凸性,我們一定只會使用將方向 (X,Y)(X,Y) 夾在中間的兩種向量。
由此,二分答案,找到這兩種向量,判斷答案是否合法即可。

時間複雜度 O(TLogV)O(TLogV)O(TLog2V)O(TLog^2V)
以下代碼實現的是 O(TLog2V)O(TLog^2V) 的解法。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
void exgcd(int a, int b, int &x, int &y) {
	if (b == 0) {
		x = 1, y = 0;
		return;
	}
	int q = a / b, r = a % b;
	exgcd(b, r, y, x);
	y -= q * x;
}
int inv(int x, int p) {
	int a = 0, b = 0;
	exgcd(x, p, a, b);
	return (a % p + p) % p;
}
struct info {int x, y, c; } q[MAXN];
int top, a, b, c, x, y;
void work(int c, int d){
	q[top = 0] = (info) {0, 0, 0};
	int x, a = 1, b = 0;
	while (d != 0) {
		info tmp = q[top];
		q[++top] = (info) {tmp.x + c / d * a, tmp.y + c / d * d, c / d};
		for (int t = 1; t <= 2 && d != 0; t++){
			if (t == 1) b += c / d * a;
			else a += c / d * b;
			x = c % d, c = d, d = x;
		}
	}
}
ll func(ll x, ll y) {
	if (x < 0) return -1;
	else return x / y;
}
int main() {
	int T; read(T);
	while (T--) {
		read(a), read(x), read(b), read(y), read(c);
		int g = __gcd(a, b); a /= g, b /= g, c /= __gcd(c, g);
		g = __gcd(a, c), a /= g, c /= g, y /= g;
		g = __gcd(b, c), b /= g, c /= g, x /= g;
		a %= c, b %= c;
		if (c == 1) {
			printf("%d\n", x + y);
			continue;
		}
		int d = 1ll * a * inv(b, c) % c; work(c, d);
		if (q[top].x != c) q[++top] = (info) {c, c, 1};
		int ans = 0;
		for (int i = 1; i <= top; i++) {
			int lx = q[i - 1].x, rx = q[i].x;
			int ly = c - q[i - 1].y, ry = c - q[i].y;
			int dx = (rx - lx) / q[i].c, dy = (ly - ry) / q[i].c;
			int l = ans + 1, r = x + y;
			while (l <= r) {
				int mid = (0ll + l + r) / 2;
				ll s = func(x - 1ll * mid * lx, dx);
				ll t = func(y - 1ll * mid * ry, dy);
				if (s >= 0 && t >= 0 && s + t >= 1ll * q[i].c * mid) ans = mid, l = mid + 1;
				else r = mid - 1;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章