Pinely Round 3 (Div. 1 + Div. 2)

A

构造题,分两种情况考虑

  • 上下都行,左右选一个
  • 左右都行,上下选一个
void solve() {
	int n;
	cin >> n;
	vector<pair<int, int> > a(n);
	for(auto &t : a) cin >> t.x >> t.y;
	sort(a.begin(), a.end());
	bool okx = a[0].x * a.back().x >= 0;
	for(auto &t : a) swap(t.x, t.y);
	sort(a.begin(), a.end());
	bool oky = a[0].x * a.back().x >= 0;
	cout << (okx | oky ? "YES\n" : "NO\n");
}

B

也是构造,这里介绍两种方法

法一 : 二进制拆分

考虑只去模 \(2^k\)
把每个数二进制拆分,模 \(2^k\) 的结果即为这个数的 $[0, k - 1] $位
一直往上枚举 \(k\),直到所有数的 $[0, k - 2] $位相同,第 \(k - 1\) 位不同

void solve() {
	int n;
	cin>> n;
	vector<ll> a(n);
	for(ll &x : a) cin >> x;
	auto check = [&](ll p) -> bool {
		set<ll> se;
		for(int i = 0; i < n; ++ i) se.insert(a[i] % p); 
		return se.size() == 2;
	};
	for(int i = 1; ; ++ i) {
		if(check(1ll << i)) {
			cout << (1ll << i) <<'\n';
			return;
		}
	}
}

法二 : 数学

\[x = gcd\{a[1] - a[0], a[2] - a[1], a[3]- a[2], ... , a[n - 1] - a[n - 2]\} \]

此时

\[ans = 2x \]

考虑去如何证明
不难得到

\[\forall i \in [1, n),\hspace{0.3cm} x \mid a[i] - a[i - 1] \]

换句话说,此时所有数模\(x\)结果相同
不妨设

\[a[i] = p_ix + q \]

  • \(p_i\)为偶数,则\(a[i] \bmod 2x = q\)
  • \(p_i\)为奇数,则\(a[i] \bmod 2x = x + q\)

由于 \(q < x\),所以 \(x + q < 2x\)
\(x \neq 0\),所以 \(q \neq x + q\)

情况一: \(p\) 中既有奇数又有偶数,显然成立
情况二: \(p\) 全为奇数或全为偶数,则此时 \(gcd\{a[i] - a[i - 1]\}\) 一定是 \(2x\)的倍数, 与最大为 \(x\) 矛盾

void solve() {
	int n;
	cin >> n;
	ll ans = 0;
	vector<ll> a(n);
	for(int i = 0; i < n; ++ i) {
		cin >> a[i];
		if(i) ans = gcd(ans, abs(a[i] - a[i - 1]));
	}
	cout << ans * 2 << '\n';
}

D. Split Plus K

void solve() {
	ll n, k;
	cin >> n >> k;
	vector<ll> a(n);
	for(auto &x : a) cin >> x;
	sort(a.begin(), a.end());
	if(a[0] == a[n - 1]) cout << "0\n";
	else if(a[0] <= k && a[n - 1] >= k) cout << "-1\n";
	else {
		ll t = 0, ans = 0;
		for(auto x : a) t = __gcd(t, x - k); 
		for(auto x : a) ans += (x - k) / t - 1;
		cout << ans << '\n';
	}
}

E. Multiple Lamps

vector<int> ans[20];

void init() {
	for(int n = 1; n < 20; ++ n) {
		vector<int> f(n + 1, 0);
		for(int i = 1; i <= n; ++ i) {
			for(int j = i; j <= n; j += i) f[i] |= 1 << j;
		}
		for(int i = 1; i < 1 << n; ++ i) {
			int t = 0;
			for(int j = 1; j <= n; ++ j) if((i << 1) >> j & 1) t ^= f[j];
			if(__builtin_popcount(t) <= n / 5) ans[n].push_back(i << 1);
		}
	}
	
}

void solve() {
	int n, m;
	cin >> n >> m;
	vector<pair<int, int> > a(m);
	for(auto &[x, y] : a) cin >> x >> y;
	if(n >= 20) {
		cout << n << '\n';
		for(int i = 1; i <= n; ++ i) cout << i << ' ';
		cout << '\n';
	}
	else {
		for(auto sta : ans[n]) {
			bool ok = 1;
			for(auto &[x, y] : a) if((sta >> x & 1) && !(sta >> y & 1)) ok = 0;
			if(ok) {
				cout << __builtin_popcount(sta) << '\n';
				for(int i = 1; i <= n; ++ i) if(sta >> i & 1) cout << i << ' ';
				cout << '\n';
				return;
			}
		}
		cout << "-1\n";
	}
}

F1. Small Permutation Problem (Easy Version)

void solve() {
	int n, ok = 1;
	cin >> n;
	vector<int> a(n + 1, 0);
	for(int i = 1; i <= n; ++ i) {
		cin >> a[i];
		ok &= a[i] <= i && a[i] >= a[i - 1] && a[i] <= a[i - 1] + 2;
	}
	if(!ok || a[n] != n) cout << "0\n";
	else {
		ll ans = 1;
		for(int i = 1; i <= n; ++ i) {
			int delta = a[i] - a[i - 1];
			if(delta == 1) ans = ans * (2 * (i - a[i - 1]) - 1) % P;
			if(delta == 2) ans = ans * (i - a[i - 1] - 1) % P * (i - a[i - 1] - 1) % P;
		}
		cout << ans << '\n';
	}
}

F2. Small Permutation Problem (Hard Version)

ll calc(int a, int b, int k) {
	return C(a, k) * C(b, k) % P * fac[k] % P;
}

void solve() {
	int n;
	cin >> n;
	vector<int> a(n + 1, 0);
	for(int i = 1; i <= n; ++ i) cin >> a[i];
	if(a[n] != n && a[n] != -1) return cout << "0\n", void();
	
	ll ans = 1;
	auto work = [&](int i, int j) {
		ll cur = 0;
		int delta = a[i] - a[j];
		for(int k = 0; k <= delta; ++ k) {
			cur = (cur + calc(i - j, i - a[j] - k, delta - k) * calc( i - j, j - a[j], k)) % P;
		}
		ans = ans * cur % P;	
	};
	
	int i = 1, j = 0;
	for(; i <= n; ++ i) {
		if(~ a[i]) {
			if(a[i] < a[j]) return cout << "0\n", void();
			work(i, j);
			j = i;
		}
	}
	
	work(a[n] = n, j);
	cout << ans << '\n';
}
posted @ 2024-01-02 22:59  Lu_xZ  阅读(78)  评论(0编辑  收藏  举报