某岛

… : "…アッカリ~ン . .. . " .. .
August 2, 2013

SRM 586

250. PiecewiseLinearFunction

Brief description:

… 给定一个分段线性 (piecewise linear) 函数。。
。。问 f(x) = k 最多可以有多少个解 (k∈R)。若可以有无限多解则返回 -1。

Analysis:

先判断无解。。然后线段树求最大覆盖次数。。注意端点处只被覆盖一次。需要开始全部*2然后拆点。
。。当然这种预处理后一次询问的问题。。可以用离线算法 ———— +1-1 标记数组 + 排序来解决。。
。。当然 O(n2) 暴力不容易写错。。。

500. History

Brief description:

… 有 n 个国家。。每个国家有一些朝代。朝代都是从 0 开始纪年。
。。给定每个朝代的持续时间,两个朝代被称为同时代的。。如果这两个朝代中存在一对纪年表示的是同一年。
。现在给定一些同时代关系。。问是否另一些朝代之间也可能是同时代的。。。

Analysis:

。。差分约束模型。。

1000. StringWeight

Brief description:

… 一个字符串含有 26 个英文字母。。一个字符串的权值。。记作所有至少出现过一次的字符、出现的最右边位置减去最左边位置。。。
。。一个字符串被称为是 “轻的”。。如果在所有相同长度的字符串中。。没有权值比它更小的。。。。
现在给定一个数组 L[0], L[1], … L[n-1] …
要求你用长度分别为 L[0], L[1], … L[n-1] 的 “轻的” 字符串依次连接成一个大字符串。。。
、。。。最小化这个大字符串的权值。。

Analysis:

… 首先。。对于一个 “轻的” 字符串。。一定要最大限度的用满 26 的字符。。
。。然后重复多次的字符。。一定都是在一块连续的位置。。。

当我们以及处理了一部分字符串。。。考察下一个字符串的某个字符时。。它可能处于以下三种状态之一:

白色 (White):尚未出现。
灰色 (Gray): 已经出现。
黑色 (Black): 已经终止。

知道其中两个就行了。。

我们有 White -> Gray, Gray -> Black 以及在当前这个字符串中直接 White -> Black 三种转移。。
这些需要枚举。。。

。。YY 出状态。。以每一段小字符串划分阶段。。。

const int N = 60, Z = 27;
int dp[N][Z][Z]; //Gray, White

class StringWeight {
public:
  int getMinimum(vector <int> L) {

	    int n = SZ(L); FLC(dp, 0x3f), dp[0][0][26] = 0;

	    REP_3(i, j, k, n, 27, 27) if (dp[i][j][k] != INF){
	        REP_2(jj, kk, j+1, k+1){ // Black, Gray ..
	            if (j + kk < min(26, L[i]) || jj + kk > L[i]) continue;
	            int b = dp[i][j][k] + (jj-1)*jj/2 + (j-jj)*L[i];
	            if (jj + kk == 26) b += L[i] - 26;
	            REP(jjj, kk+1) checkMin(dp[i+1][j-jj+jjj][k-kk], b += jjj);
	        }
	    }

		int res = INF; REP_2(i, j, Z, Z) checkMin(res, dp[n][i][j]);
		return res;
	}
};

dp[i][j][k]: 表示当前考察到第 i 个字符串,j 个灰色字符,k 个白色字符的最小权值。
。。状态 O(NZ^2) 。。转移 O(Z^3)。。

来具体分析转移。。Gray -> Black 一定是从最左边开始关闭。。所以加等差数列 (jj-1)*jj/2 即可。
Gray -> Gray 。。比较糟糕。。每一类都要增加 L[i] 的损耗。。
White -> Black 。。无损耗。
White -> Gray 。。这类尽量往右边填。。也是一个等差数列。。。

External link:

https://apps.topcoder.com/wiki/display/tc/SRM+586
https://gist.github.com/lychees/6140957