Skip to content

Instantly share code, notes, and snippets.

@amoshyc
Last active August 29, 2015 06:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amoshyc/d0d2135951ff175e27e0 to your computer and use it in GitHub Desktop.
Save amoshyc/d0d2135951ff175e27e0 to your computer and use it in GitHub Desktop.
Poj 3484: ShowStopper

Poj 3484: ShowStopper

分析

這題不太容易看出來是二分搜…倒是更讓人想到利用 xor。這題另一個難點是 IO , 據說卡 cin/cout,還有這題的題目也不易讀懂啊。

X Y Z

可以展開成一個數列

<X, X+Z, X+2Z, ...> (X + K * Z <= Y)

1 10 1 為例,可以展開成 <1, 2, 3, 4, ..., 10>

另一個例子 2 10 1 則展開成 <2, 3, 4, ..., 10>

題目要求的是在這筆測資內,哪一個數(保證只有一個)的出現次數為奇數,輸出此數與其出現次數

正負相關性判定

Let O[1], O[2], ... 代表各數的出現次數

其中 O[p] is odd, others is even

我們設

int C[i] = O[1] + O[2] + ... + O[i]

偶數 + 偶數 = 偶數
偶數 + 奇數 = 奇數

可知

for all i < p, C[i] is even
for all i >= p, C[i] is odd

也就是說 C[i] 表為

偶偶偶奇奇奇奇

正負相關性出現了,二分搜可以用了…

所以我們得到策略:對 p 二分搜,藉由判斷 C(p) 是否為奇數,即從

0 0 0 1 1 1 1

中找出第一個 1 是在哪

上下界判定

解的範圍 = [1, max_y],使用 (lb, ub]

判斷函式實作

由定義可知,C(i) 代表 1, 2, 3, ..., i 這些數的出現次數總和。 要得到這個總和,我們計算該筆測資展開所有數列後,有幾個 <= i 的數, 因為所有的數列都是等差數列,我們可以利用等差公式來計算,並不用真的把數列展開。

其它

無解的情況(輸出 "no corruption")發生在對所有的 iC[i] 都為 even, 這可以預先判斷掉,藉由判斷 C(max_y) 是否是偶數(即所有數的出現次數總和)。

題目還要求輸出 p 的出現次數 O(p),這可以利用 C(i) 的定義得到,即 C(p) - C(p-1)

AC Code

#include <iostream>
#include <algorithm>
#include <vector>
#include <sstream>
#include <cstdio>
#include <cstring>
#include <cstdlib>

using namespace std;

typedef long long ll;

struct S {
	ll x, y, z;
};

vector<S> data;
int N;

ll C(ll p) {
	// 計算展開的數列中大於等於 p 的數有幾個
	ll sum = 0;
	for (int i = 0; i < N; i++) {
		if (p < data[i].x)
			continue;
		ll end_term = min(p, data[i].y);
		sum += (end_term - data[i].x) / data[i].z + 1;
	}
	return sum;
}

void solve() {
	N = data.size();
	// 解的範圍 = [1, maxY]
	// 偶偶偶奇奇奇奇 = 0 0 0 1 1 1 1
	// (lb, ub]

	ll max_y = -1;
	for (size_t i = 0; i < N; i++)
		if (data[i].y > max_y)
			max_y = data[i].y;

	// when all C[i] is even
	if (C(max_y) % 2 == 0) {
		puts("no corruption");
		return;
	}


	ll lb = 0;
	ll ub = max_y;

	while (ub - lb > 1) {
		ll mid = (lb + ub) / 2;
		if (C(mid) % 2 == 1) ub = mid;
		else lb = mid;
	}

	printf("%lld %lld\n", ub, C(ub) - C(lb));
}

int main() {
	char inp[50];
	while (fgets(inp, 50, stdin) != NULL) {
		size_t len = strlen(inp);
		if (len >= 1 && inp[len-1] == '\n') {
			inp[len-1] = '\0';
			len--;
		}

		if (len == 0) {
			if (data.size() != 0) {
				solve();
				data.clear();
			}
		}
		else {
			S s; sscanf(inp, "%lld %lld %lld", &s.x, &s.y, &s.z);
			data.push_back(s);
		}
	}

	if (data.size() != 0)
		solve();

	return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment