AtCoder Beginner Contest 185題解(模擬、背包、貪心、線性dp、樹狀數組)


這場好水啊。。。手速場,手速不夠還是不行啊。


A - ABC Preparation

簽到題,取四個值當中最小的即可。

#include <bits/stdc++.h>
using namespace std;
int main() {
	int ans = 0x3f3f3f3f;
	for (int i = 0; i < 4; i++) {
		int x;
		cin >> x;
		ans = min(ans, x);
	}
	printf("%d", ans);
	return 0;
}

B - Smartphone Addiction

直接模擬,對於每個充電和耗電的區間計算是否滿足要求即可。

#include <bits/stdc++.h>
using namespace std;
int n, m, t, limit;
int a, b, lst;
int main() {
	cin >> n >> m >> t;
	limit = n;
	for (int i = 1; i <= m; i++) {
		cin >> a >> b;
		n -= a - lst;
		if (n <= 0) {
			puts("No");
			return 0;
		}
		n += b - a;
		n = min(n, limit);
		lst = b;
	}
	n -= t - lst;
	if (n <= 0) {
		puts("No");
		return 0;
	}
	puts("Yes");
	return 0;
}

C - Duodecim Ferra

直接背包dp,記 \(f[i][j]\) 代表用 \(i\) 個正整數湊出 \(j\) 的方案數,\(f[i][j]+=f[i-1][j-k]\),注意因為是正整數所以當 \(j<i\)\(f[i][j]=0\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int L;
ll f[15][205];
int main() {
	scanf("%d", &L);
	f[0][0] = 1;
	for (int i = 1; i <= 12; i++) {
		for (int k = 1; k <= L; k++) {
			for (int j = L; j >= max(k, i); j--) {
				f[i][j] += f[i - 1][j - k];
			}
		}
	}
	printf("%lld", f[12][L]);
	return 0;
}

D - Stamp

題意比較迷惑,看了樣例才懂。

直接取每一段白色的長度的最小值,\(k\) 一定不能大於這個,而 \(k\) 越大越好,所以 \(k\) 一定等於這個。然后再對每一個空隙計算,設某一段是 \(L\),則需 \(\lceil\frac{L}{k}\rceil\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m, a[200005];
ll ans;
int gcd(int x, int y) {
	return y == 0 ? x : gcd(y, x % y);
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) scanf("%d", &a[i]);
	sort(a + 1, a + 1 + m);
	int lst = 0, g = 1e9 + 7;
	a[++m] = n + 1;
	for (int i = 1; i <= m; i++) {
		if (a[i] - lst - 1 != 0) g = min(g, a[i] - lst - 1);
		lst = a[i];
	}
	lst = 0;
	for (int i = 1; i <= m; i++) {
		if (a[i] - lst - 1 != 0) ans += (a[i] - lst - 1 + g - 1) / g;
		lst = a[i];
	}
	printf("%lld", ans);
	return 0;
}

E - Sequence Matching

思博dp題,記 \(dp[i][j]\) 為答案,有方程 \(dp[i][j]=min(dp[i-1][j],dp[i][j-1])+1\),這是第一種轉移,意義是刪掉 \(i\) 或者 \(j\)

\(a[i]=b[j]\) 則還可以從 \(dp[i-1][j-1]\) 轉移,因為有 \(a[i],b[j]\) 這一對不會影響答案。若沒有則還可以 \(dp[i-1][j-1]\) 意義也是不刪但是 \(y + 1\)

注意初始化 \(dp[i][0]=i,dp[0][j]=j,dp[0][0]=0\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m, a[1005], b[1005];
int dp[1005][1005];
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	for (int i = 1; i <= m; i++) scanf("%d", &b[i]);
	memset(dp, 0x3f, sizeof(dp));
	dp[0][0] = 0;
	for (int i = 1; i <= n; i++) dp[i][0] = i;
	for (int i = 1; i <= m; i++) dp[0][i] = i;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (a[i] == b[j]) dp[i][j] = min(dp[i][j], dp[i - 1][j - 1]);
			dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1);
			dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1);
			dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + 1);
		}
	}
	printf("%d", dp[n][m]);
	return 0;
}

F - Range Xor Query

考慮第二種操作可以用前綴異或和做,\(sum(l,r)=sum(1,r)\text{^}sum(1,l-1)\),所以我們可以維護前綴和。對於第一種操作可以看成單調加(異或滿足交換律),所以可以用樹狀數組維護,基本就是樹狀數組板子改幾個運算符。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m;
int a[300005];
int BIT[300005];
void add(int x, int v) {
	while (x <= n) {
		BIT[x] ^= v;
		x += (x & (-x));
	}
}
int ask(int x) {
	int ret = 0;
	while (x) {
		ret ^= BIT[x];
		x -= (x & (-x));
	}
	return ret;
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		add(i, a[i]);
	}
	for (int i = 1; i <= m; i++) {
		int t, x, y;
		scanf("%d%d%d", &t, &x, &y);
		if (t == 1) {
			add(x, y);
		} else {
			printf("%d\n", ask(y) ^ ask(x - 1));
		}
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM