1. 程式人生 > >【CodeForces】CodeForces Round #511 (Div. 1) 題解

【CodeForces】CodeForces Round #511 (Div. 1) 題解

【比賽連結】

【題解連結】

**【A】**Enlarge GCD

【思路要點】

  • 令所有數的 g c d gcd
    g g ,將所有數除去 g g ,問題變為了所有數的 g
    c d gcd
    1 1 的情況。
  • 我們要選出一個最大的數集,使得這個數集中的數存在不為 1
    1
    的公因數。
  • 顯然我們只需要考慮所有質數即可,線性篩求出每個數的最小質因子,質因數分解每一個數即可。
  • 時間複雜度 O ( N L o g V + V ) O(NLogV+V)

【程式碼】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
const int MAXV = 1.5e7 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
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;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int n, tot, a[MAXN], prime[MAXV], f[MAXV], cnt[MAXV];
void init(int n) {
	for (int i = 2; i <= n; i++) {
		if (f[i] == 0) prime[++tot] = f[i] = i;
		for (int j = 1; j <= tot && prime[j] <= f[i]; j++) {
			int tmp = prime[j] * i;
			if (tmp > n) break;
			f[tmp] = prime[j];
		}
	}
}
int gcd(int x, int y) {
	if (y == 0) return x;
	else return gcd(y, x % y);
}
int main() {
	init(1.5e7);
	int g = 0; read(n);
	for (int i = 1; i <= n; i++) {
		read(a[i]);
		g = gcd(a[i], g);
	}
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		int tmp = a[i] / g;
		while (tmp != 1) {
			cnt[f[tmp]]++;
			if (cnt[f[tmp]] > ans) ans = cnt[f[tmp]];
			int tnp = f[tmp];
			while (tmp % tnp == 0) tmp /= tnp;
		}
	}
	if (ans == 0) printf("-1\n");
	else printf("%d\n", n - ans);
	return 0;
}

**【B】**Little C Loves 3 II

【思路要點】

  • 打表題。
  • 不妨令 N M N≤M
  • 用最大流求出 N , M N,M 較小的時候的答案,我們發現當 N , M N,M 足夠大時,答案為 2 N M 2 2*\lfloor\frac{N*M}{2}\rfloor ,特殊處理 N = 1 N=1 的情況即可。
  • 或者你也可以直接交一張表。
  • 時間複雜度 O ( 1 ) O(1)

【程式碼】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
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;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int main() {
	ll n, m; read(n), read(m);
	if (n > m) swap(n, m);
	if (n == 1) {
		ll ans = m / 6 * 6;
		ll tmp = m % 6;
		ans += max(0ll, tmp - 3) * 2;
		writeln(ans);
	} else if (n == 2) {
		ll ans = n * m;
		if (m == 2) ans -= 4;
		if (m == 3) ans -= 2;
		if (m == 7) ans -= 2;
		writeln(ans);
	} else writeln(n * m - n * m % 2);
	return 0;
}

**【C】**Region Separation

【思路要點】

  • 1 1 號節點為根,節點 i i 的子樹權值和為 s u m i sum_i
  • 若給定 k k ,一棵樹能夠被分成權值和相同的 k k 部分的充要條件為 s u m 1 k \frac{sum_1}{k} 為整數,並且存在 k k 個子樹 i i 滿足 s u m i sum_i s u m 1 k \frac{sum_1}{k} 的整數倍。
  • 因此,我們可以先計算出對於每一個 k k ,滿足 s u m i sum_i s u m 1 k \frac{sum_1}{k} 的整數倍的子樹 i i 的個數 c n t k cnt_k ,然後,在合法的 k k 上簡單 d p dp ,得到答案。
  • 考慮一個子樹 i i c n t k cnt_k 的貢獻,由於 s u m i = t s u m 1 k   ( t Z ) sum_i=\frac{t*sum_1}{k}\ (t\in \Z)