【AtCoder】Tokio Marine & Nichido Fire Insurance Programming Contest 2020

比賽鏈接

點擊打開鏈接

官方題解

點擊打開鏈接

Problem A. Nickname

輸出 s1s2s3s_1s_2s_3 即可。
時間複雜度 O(S)O(|S|)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 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 main() {
	scanf("%s", s + 1), s[4] = 0;
	printf("%s\n", s + 1);
	return 0;
}

Problem B. Tag

判斷 T×(VW)T\times (V-W)AB|A-B| 的大小關係即可。
時間複雜度 O(1)O(1)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 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;
}
int main() {
	int a, v, b, w, t;
	read(a), read(v), read(b), read(w), read(t);
	int dist = abs(a - b);
	if (v > w && 1ll * t * (v - w) >= dist) puts("YES");
	else puts("NO");
	return 0;
}

Problem C. Lamps

考慮初始時 Ai=0A_i=0 的情況,則經過 O(LogN)O(LogN) 次操作後,應當有 Ai=NA_i=N
因此,有效操作的輪數不會超過 O(LogN)O(LogN) 。模擬,直到 Ai=NA_i=N 或是操作次數用盡即可。

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

#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;
}
int n, k, a[MAXN];
bool work() {
	static int s[MAXN];
	memset(s, 0, sizeof(s));
	for (int i = 1; i <= n; i++) {
		int l = max(1, i - a[i]), r = min(n, i + a[i]);
		s[l]++, s[r + 1]--;
	}
	bool res = false;
	for (int i = 1; i <= n; i++) {
		s[i] += s[i - 1];
		if (s[i] != a[i]) {
			res = true;
			a[i] = s[i];
		}
	}
	return res;
}
int main() {
	read(n), read(k);
	for (int i = 1; i <= n; i++)
		read(a[i]);
	for (int i = 1; i <= k; i++)
		if (!work()) break;
	for (int i = 1; i <= n; i++)
		printf("%d ", a[i]);
	printf("\n");
	return 0;
}

Problem D. Knapsack Queries on a tree

一種可行的暴力是記 dpi,jdp_{i,j} 表示考慮節點 ii 及其祖先,剩餘 jj 容量的揹包的最優解。
dpidp_{i} 顯然可以通過 O(L)O(L) 的掃描由 dpi2dp_{\lfloor\frac{i}{2}\rfloor} 轉移得到。
該做法的預處理複雜度爲 O(N×L)O(N\times L) ,單組詢問的複雜度爲 O(1)O(1)

另一種可行的暴力是直接枚舉選取物品的集合。
由於樹高不超過 O(LogN)O(LogN) ,該做法的預處理複雜度爲 O(1)O(1) ,單組詢問的複雜度爲 O(N)O(N)

α=O(N)\alpha=O(\sqrt{N}) ,按照第一種方法計算 dpi  (iα)dp_{i}\;(i\leq \alpha) ,則可以 O(1)O(1) 回答出現位置 α\leq \alpha 的詢問。
對於剩餘詢問,枚舉 α\geq \alpha 的物品是否選取,並用 dpdp 值計算 α\leq \alpha 的物品的最優選取方案即可。

時間複雜度 O((L+Q)N)O((L+Q)\sqrt{N})

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
const int MAXV = 1e5 + 5;
const int MAXM = 1 << 9;
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 a[MAXM][MAXV];
int n, m, r, q, v[MAXN], w[MAXN];
int query(int x, int y) {
	if (x <= m) return a[x][y];
	else {
		int ans = query(x / 2, y);
		if (y >= w[x]) chkmax(ans, v[x] + query(x / 2, y - w[x]));
		return ans;
	}
}
int main() {
	read(n), m = (1 << 9) - 1, r = 1e5;
	for (int i = 1; i <= n; i++)
		read(v[i]), read(w[i]);
	for (int i = 1; i <= m; i++) {
		int f = i / 2;
		for (int j = 1; j <= r; j++) {
			a[i][j] = a[f][j];
			if (j >= w[i]) chkmax(a[i][j], v[i] + a[f][j - w[i]]);
		}
	}
	read(q);
	for (int i = 1; i <= q; i++) {
		int x, y; read(x), read(y);
		printf("%d\n", query(x, y));
	}
	return 0;
}

Problem E. O(rand)

不妨認爲 S=0,T=2k1S=0,T=2^k-1 ,且 SAiTS\leq A_i\leq T
則題目中的要求等價於:對於每一個二進制位,選出的集合既有 00 ,也有 11

考慮枚舉選擇的集合中第一個元素,則對於每個二進制位,已經存在了 0,10,1 中的一者。
剩餘問題可轉換爲:選擇一個集合,使得集合的二進制與的結果爲 00 ,求方案數。
則用 FWT 配合容斥原理解決轉化後的問題即可。

時間複雜度 O(N×VLogV+N2)O(N\times VLogV+N^2)
官方題解中,給出了一種複雜度更爲優秀的解法。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 55;
const int MAXV = 1 << 18;
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 coef[MAXN], binom[MAXN][MAXN];
int cnt[MAXV], bits[MAXV];
int m, goal, n, k, s, t, bit[MAXN], a[MAXN];
bool inc(int x, int y) {
	return (x | y) == x;
}
void FWTOR(int *a, int N) {
	for (int len = 2; len <= N; len <<= 1)
	for (int s = 0; s < N; s += len)
	for (int i = s, j = s + len / 2; j < s + len; i++, j++)
		a[i] = a[i] + a[j];
}
int main() {
	read(m), read(k), read(s), read(t);
	if (!inc(t, s)) {
		puts("0");
		return 0;
	}
	for (int i = 1; i <= m; i++) {
		int x; read(x);
		if (inc(x, s) && inc(t, x)) a[++n] = x;
	}
	m = 0, goal = 0;
	for (int i = 1; i <= 18; i++) {
		bit[i] = 1 << (i - 1);
		if ((t & bit[i]) && (s & bit[i]) == 0) m++, goal = goal * 2 + 1;
	}
	for (int i = 1; i <= n; i++) {
		int res = 0;
		for (int j = 1; j <= 18; j++)
			if ((t & bit[j]) && (s & bit[j]) == 0) {
				if (a[i] & bit[j]) res = res * 2 + 1;
				else res = res * 2;
			}
		a[i] = res;
	}
	for (int i = 0; i <= n; i++) {
		binom[i][0] = 1;
		for (int j = 1; j <= i; j++)
			binom[i][j] = binom[i - 1][j - 1] + binom[i - 1][j];
		for (int j = 0; j <= k - 1; j++)
			coef[i] += binom[i][j];
	}
	for (int i = 1; i <= goal; i++)
		bits[i] = bits[i / 2] + i % 2;
	ll ans = 0;
	for (int i = 1; i <= n; i++) {
		memset(cnt, 0, sizeof(cnt));
		for (int j = i + 1; j <= n; j++)
			cnt[a[i] ^ a[j] ^ goal]++;
		FWTOR(cnt, goal + 1);
		for (int j = 0; j <= goal; j++)
			if (bits[j] & 1) ans -= coef[cnt[j]];
			else ans += coef[cnt[j]];
	}
	cout << ans << endl;
	return 0;
}

Problem F. Triangles

不失一般性地,考慮頂點在 (0,i),(j,0),(W,k)(0,i),(j,0),(W,k) 處的三角形。
由對稱性,考慮僅計算 iki\leq k 的情況,令 k=i+dk=i+d

由畢克定理,三角形內部的點數 AA ,邊界上的點數 BB ,面積 SS 應當滿足
2S=2A+B22S=2A+B-2

也即
(2i+d)Wij(Wj)(i+d)=2A+gcd(i,j)+gcd(W,d)+gcd(Wj,i+d)2(2i+d)W-ij-(W-j)(i+d)=2A+gcd(i,j)+gcd(W,d)+gcd(W-j,i+d)-2

整理得
iWgcd(i,j)gcd(Wj,i+d)=2A+gcd(W,d)2djiW-gcd(i,j)-gcd(W-j,i+d)=2A+gcd(W,d)-2-dj

因此,我們需要計算滿足如下不等式的 (i,j,d)(i,j,d) 的個數:
iWgcd(i,j)gcd(Wj,i+d)2K+gcd(W,d)2djiW-gcd(i,j)-gcd(W-j,i+d)\leq 2K+gcd(W,d)-2-dj

考慮枚舉 (j,d)(j,d) 則不等式的右側應當爲一個定值。
由於 gcd(i,j)+gcd(Wj,i+d)j+(Wj)=Wgcd(i,j)+gcd(W-j,i+d)\leq j+(W-j)=W ,即不等式左側關於 ii 單調。
因此,我們可以 O(1)O(1) 算出滿足不等式的 ii 的個數。

又因爲使得不等式右側 0\geq 0(j,d)(j,d) 的組數不超過 O(VLogV)O(VLogV) ,枚舉即可。

時間複雜度 O(VLog2V)O(VLog^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;
}
int n, m, k;
ll work(int n, int m) {
	ll ans = 0;
	for (int i = 0; i <= n - 2; i++)
	for (int j = 1; j <= m - 1 && i * j <= 2 * k + m; j++) {
		int tmp = 2 * k + __gcd(i, m) - i * j - 2;
		if (tmp >= 0) {
			int limit = min(n - 1 - i, tmp / m + 1);
			ans += (limit - (m * limit - __gcd(limit, j) - __gcd(limit + i, m - j) > tmp)) * (1 + (i != 0));
		}
	}
	return ans;
}
int main() {
	read(n), read(m), read(k);
	cout << work(n, m) * 2 + work(m, n) * 2 << endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章