BZOJ 1963 最小和

题目:BZOJ 1963 最小和
(笔者注:出处似乎是 TopCoder SRM 456 Div.1 1050pts FunctionalEquation)

题意:

给定 C C C N N N,并用伪随机的方法给出 ( x i , y i ) (x_i, y_i) (xi,yi) ( i = 0 , 1 , … , N − 1 ) (i = 0, 1, \ldots, N - 1) (i=0,1,,N1),找到一个整数到整数的映射 f : Z → Z f : \mathbb{Z} \to \mathbb{Z} f:ZZ,使得对于任意整数 x x x,有 f ( 2 f ( x ) − x + 1 ) = f ( x ) + C f(2 f(x) - x + 1) = f(x) + C f(2f(x)x+1)=f(x)+C,在此基础上最小化 ∑ i = 0 N − 1 ∣ f ( x i ) − y i ∣ \sum_{i = 0}^{N - 1}{|f(x_i) - y_i|} i=0N1f(xi)yi

1 ≤ C ≤ 16 1 \leq C \leq 16 1C16, 1 ≤ N ≤ 1 0 4 1 \leq N \leq 10^4 1N104, 0 ≤ x i , y i < 1 0 9 0 \leq x_i, y_i < 10^9 0xi,yi<109

题解:

观察 f f f 的限制条件,有
f ( x ) + 2 C = ( f ( x ) + C ) + C = f ( 2 f ( x ) − x + 1 ) + C = f ( 2 f ( 2 f ( x ) − x + 1 ) − ( 2 f ( x ) − x + 1 ) + 1 ) = f ( 2 ( f ( x ) + C ) − 2 f ( x ) + x ) = f ( x + 2 C ) \begin{aligned} & f(x) + 2 C \\ = & (f(x) + C) + C \\ = & f(2 f(x) - x + 1) + C \\ = & f(2 f(2 f(x) - x + 1) - (2 f(x) - x + 1) + 1) \\ = & f(2(f(x) + C) - 2 f(x) + x) \\ = & f(x + 2 C) \end{aligned} =====f(x)+2C(f(x)+C)+Cf(2f(x)x+1)+Cf(2f(2f(x)x+1)(2f(x)x+1)+1)f(2(f(x)+C)2f(x)+x)f(x+2C)
于是只要确定了 f ( 0 ) , f ( 1 ) , … , f ( 2 C − 1 ) f(0), f(1), \ldots, f(2 C - 1) f(0),f(1),,f(2C1) 的取值,必然能确定整个映射。

注意到在 f ( x ) f(x) f(x) 确定的同时,除了 f ( x + 2 k C ) f(x + 2 k C) f(x+2kC) ( k ∈ Z ) (k \in \mathbb{Z}) (kZ) 的取值会确定,它也会确定 f ( 2 f ( x ) − x + 1 + 2 k C ) f(2 f(x) - x + 1 + 2 k C) f(2f(x)x+1+2kC) ( k ∈ Z ) (k \in \mathbb{Z}) (kZ) 的取值,而 x x x ( 2 f ( x ) − x + 1 ) (2 f(x) - x + 1) (2f(x)x+1) 奇偶性不同,所以它们在模 2 C 2 C 2C 意义下一定不相同,进一步推理可得,模意义下的每个奇数剩余类恰好会和一个偶数剩余类配对。

不失一般性地,令 x ≡ 2 u , 2 f ( x ) − x + 1 ≡ 2 v + 1 ( m o d 2 C ) x \equiv 2 u, 2 f(x) - x + 1 \equiv 2 v + 1 \pmod{2C} x2u,2f(x)x+12v+1(mod2C) ( 0 ≤ u , v < C ) (0 \leq u, v < C) (0u,v<C),那么有
f ( 2 u ) ≡ f ( 2 v + 1 ) ≡ u + v ( m o d C ) f(2 u) \equiv f(2 v + 1) \equiv u + v \pmod{C} f(2u)f(2v+1)u+v(modC)

进一步地,若
f ( 2 u ) = u + v + a C   ( a ∈ Z ) f(2 u) = u + v + a C~(a \in \mathbb{Z}) f(2u)=u+v+aC (aZ)
那么有
f ( 2 v + 1 ) = f ( 2 v + 1 + 2 a C ) − 2 a C = f ( 2 ( u + v + a C ) − 2 u + 1 ) − 2 a C = f ( 2 f ( 2 u ) − 2 u + 1 ) − 2 a C = ( u + v + a C ) + C − 2 a C = u + v + ( 1 − a ) C \begin{aligned} & f(2 v + 1) \\ = & f(2 v + 1 + 2 a C) - 2 a C \\ = & f(2(u + v + a C) - 2 u + 1) - 2 a C \\ = & f(2 f(2 u) - 2 u + 1) - 2 a C \\ = & (u + v + a C) + C - 2 a C \\ = & u + v + (1 - a) C \end{aligned} =====f(2v+1)f(2v+1+2aC)2aCf(2(u+v+aC)2u+1)2aCf(2f(2u)2u+1)2aC(u+v+aC)+C2aCu+v+(1a)C

于是,对于一组剩余类配对 { ( 2 u 1 , 2 v 1 + 1 ) , ( 2 u 1 , 2 v 1 + 1 ) , … , ( 2 u k , 2 v k + 1 ) , … , ( 2 u C , 2 v C + 1 ) } \lbrace (2 u_1, 2 v_1 + 1), (2 u_1, 2 v_1 + 1), \ldots, (2 u_k, 2 v_k + 1), \ldots, (2 u_C, 2 v_C + 1) \rbrace {(2u1,2v1+1),(2u1,2v1+1),,(2uk,2vk+1),,(2uC,2vC+1)},我们只需要分别最小化 ∑ x i ≡ 2 u k ( m o d 2 C ) ∣ f ( x i ) − y i ∣ + ∑ x i ≡ 2 v k + 1 ( m o d 2 C ) ∣ f ( x i ) − y i ∣ \sum_{x_i \equiv 2 u_k \pmod{2 C}}{|f(x_i) - y_i|} + \sum_{x_i \equiv 2 v_k + 1 \pmod{2 C}}{|f(x_i) - y_i|} xi2uk(mod2C)f(xi)yi+xi2vk+1(mod2C)f(xi)yi 即可。

对于一组 ( u , v ) (u, v) (u,v),我们可以将有关的 ∣ f ( x i ) − y i ∣ |f(x_i) - y_i| f(xi)yi 均写成 ∣ a C − p i ∣ |a C - p_i| aCpi 的形式,而 ∑ i ∣ a C − p i ∣ \sum_{i}{|a C - p_i|} iaCpi 是关于整数 a a a 的分段一次函数,只需要枚举每个段里 a a a 能取到的最左或最右的位置即可确定最小值。

剩下的部分是如何求出最优的剩余类配对。在预处理每对 ( u , v ) (u, v) (u,v) 配对的最小代价后,计算二分图最小权完美匹配即可。由于 C C C 比较小,我们可以偷点懒,用 O ( C 2 C ) \mathcal{O}(C 2^C) O(C2C) 的方法计算匹配。

偷懒后的总时间复杂度为 O ( n log ⁡ n + n C + C 2 + C 2 C ) \mathcal{O}(n \log n + n C + C^2 + C 2^C) O(nlogn+nC+C2+C2C),其中 O ( C 2 C ) \mathcal{O}(C 2^C) O(C2C) 的部分可以优化到 O ( C 3 ) \mathcal{O}(C^3) O(C3)

代码:

#include 
using namespace std;
typedef long long LL;
const int maxn = (int)1e4 + 1, maxd = 17, maxs = 1 << 16 | 1, INF = 0x3f3f3f3f;
int n, m;
vector<int> lft[maxd], rht[maxd];
LL w[maxd][maxd], f[maxs];
struct Gen {
	int val, prd, adt, mod;
	void read() {
		scanf("%d%d%d%d", &val, &prd, &adt, &mod);
	}
	int get() {
		int ret = val;
		val = ((LL)val * prd + adt) % mod;
		return ret;
	}
} genX, genY;
inline void upd(LL &x, LL y) {
	x > y && (x = y);
}
int main() {
	scanf("%d%d", &m, &n);
	genX.read();
	genY.read();
	for(int i = 0; i < n; ++i) {
		int x = genX.get(), y = genY.get();
		if(x & 1) {
			int v = (x + m + m - 1) / 2 % m;
			rht[v].push_back(y - x - m + 1);
		} else {
			int u = x / 2 % m;
			lft[u].push_back(x - y);
		}
	}
	for(int i = 0; i < m; ++i) {
		sort(lft[i].begin(), lft[i].end());
		sort(rht[i].begin(), rht[i].end());
	}
	for(int u = 0; u < m; ++u)
		for(int v = 0; v < m; ++v) {
			int len = 0;
			static int seq[maxn];
			for(vector<int>::iterator it = lft[u].begin(); it != lft[u].end(); ++it)
				seq[len++] = *it;
			for(vector<int>::iterator it = rht[v].begin(); it != rht[v].end(); ++it)
				seq[len++] = *it;
			inplace_merge(seq, seq + lft[u].size(), seq + len);
			LL sL = 0, sR = 0;
			for(int i = 0; i < len; ++i) {
				seq[i] += v - u;
				sR += seq[i];
			}
			int pos = seq[0] / m * m;
			if(pos > seq[0])
				pos -= m;
			w[u][v] = sR - (LL)len * pos;
			seq[len] = INF;
			for(int i = 1; i <= len; ++i) {
				sL += seq[i - 1];
				sR -= seq[i - 1];
				if(i < len - i) {
					pos = seq[i] / m * m;
					if(pos > seq[i])
						pos -= m;
					if(pos >= seq[i - 1])
						upd(w[u][v], sR - sL + (LL)(i + i - len) * pos);
				} else {
					pos = seq[i - 1] / m * m;
					if(pos < seq[i - 1])
						pos += m;
					if(pos <= seq[i])
						upd(w[u][v], sR - sL + (LL)(i + i - len) * pos);
				}
			}
		}
	for(int i = 0; i < (1 << m); ++i) {
		int cnt = 0;
		for(int j = 0; j < m; ++j)
			cnt += (i >> j) & 1;
		if(!cnt) {
			f[i] = 0;
			continue;
		}
		bool vis = 0;
		for(int j = 0; j < m; ++j) {
			if(!((i >> j) & 1))
				continue;
			LL tmp = f[i ^ (1 << j)] + w[cnt - 1][j];
			if(vis) {
				upd(f[i], tmp);
			} else {
				f[i] = tmp;
				vis = 1;
			}
		}
	}
	printf("%lld\n", f[(1 << m) - 1]);
	return 0;
}

你可能感兴趣的:(BZOJ,二分图匹配,映射)