<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
> <channel><title>EUYUIL</title> <atom:link href="http://euyuil.com/feed/" rel="self" type="application/rss+xml" /><link>http://euyuil.com</link> <description>折腾使人进步。</description> <lastBuildDate>Wed, 08 Feb 2012 12:16:10 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <item><title>ACM/ICPC 2011 北京现场赛 Hou Yi&#8217;s Secret 题解</title><link>http://euyuil.com/3204/acm-icpc-2011-beijing-hou-yis-secret/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=acm-icpc-2011-beijing-hou-yis-secret</link> <comments>http://euyuil.com/3204/acm-icpc-2011-beijing-hou-yis-secret/#comments</comments> <pubDate>Wed, 08 Feb 2012 12:15:57 +0000</pubDate> <dc:creator>EUYUIL</dc:creator> <category><![CDATA[无类可分]]></category> <category><![CDATA[ACM]]></category> <category><![CDATA[区域赛]]></category> <category><![CDATA[水题]]></category> <category><![CDATA[现场赛]]></category> <category><![CDATA[计算几何]]></category> <category><![CDATA[题解]]></category> <guid
isPermaLink="false">http://euyuil.com/?p=3204</guid> <description><![CDATA[这是一道阴险的水题。现场赛的时候是队长 Wideas 过的，似乎过得也没有太大障碍。但是赛后我自己写，感觉题意比较模糊。如果没有看样例测试数据，可能怎么错的都不知道。 主要注意的有几点，一个是，在某处如果射了 2 箭，其实只会产生一个洞，所以重复给出的点只能算一个；还有一点，如果所有三角形的集合是 A, 以“相似关系”划分这个集合，即有 A = A1 ∪ A2 ∪ &#8230; ∪ An, 其中集合 Ai 中的三角形互相相似，那么题目要求的东西是 max { &#124;Ai&#124; }. 代码如下： #include &#60;cmath&#62; #include &#60;cstdio&#62; #include &#60;cstring&#62; #include &#60;algorithm&#62; using namespace std; const double eps = 1e-9; inline int sgn(double a) { return a &#62; eps ? 1 : a &#60; [...]]]></description> <content:encoded><![CDATA[<p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这是一道阴险的水题。现场赛的时候是队长 Wideas 过的，似乎过得也没有太大障碍。但是赛后我自己写，感觉题意比较模糊。如果没有看样例测试数据，可能怎么错的都不知道。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">主要注意的有几点，一个是，在某处如果射了 2 箭，其实只会产生一个洞，所以重复给出的点只能算一个；还有一点，如果所有三角形的集合是 A, 以“相似关系”划分这个集合，即有 A = A<sub>1</sub> ∪ A<sub>2</sub> ∪ &#8230; ∪ A<sub>n</sub>, 其中集合 A<sub>i</sub> 中的三角形互相相似，那么题目要求的东西是 max { |A<sub>i</sub>| }.</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><span
id="more-3204" ></span></p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">代码如下：</p><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;cmath&gt;
#include &lt;cstdio&gt;
#include &lt;cstring&gt;
#include &lt;algorithm&gt;
using namespace std;
const double eps = 1e-9;
inline int sgn(double a)
{
	return a &gt; eps ? 1 : a &lt; -eps ? -1 : 0;
}
inline bool eq(double a, double b)
{
	return sgn(b - a) == 0;
}
inline bool eq(double a, double b, double c)
{
	return eq(a, b) &amp;&amp; eq(b, c) &amp;&amp; eq(a, c);
}
struct point
{
	int x, y;
	inline point() { }
	inline point(const int x, const int y) : x(x), y(y) { }
	inline bool operator&lt;(const point &amp;b) const
	{
		if (x == b.x)
			return y &lt; b.y;
		return x &lt; b.x;
	}
	inline bool operator==(const point &amp;b) const
	{
		return x == b.x &amp;&amp; y == b.y;
	}
	inline point operator-(const point &amp;b) const
	{
		return point(x - b.x, y - b.y);
	}
	inline int magsqr() const
	{
		return x * x + y * y;
	}
	inline double mag() const
	{
		return sqrt((double)magsqr());
	}
};
struct triangle
{
	point a, b, c;
	double x, y, z;
	inline triangle() { }
	inline triangle(const point &amp;a, const point &amp;b, const point &amp;c) :
		a(a), b(b), c(c)
	{
		sort((point *)&amp;a, (point *)&amp;a + 3);
		x = (a - b).mag();
		y = (b - c).mag();
		z = (c - a).mag();
		sort((double *)&amp;x, (double *)&amp;x + 3);
	}
	inline bool is_valid() const
	{
		if (x + y &lt;= z || y + z &lt;= x || z + x &lt;= y)
			return false;
		point u = b - a, v = c - b;
		if (u.x * v.y == u.y * v.x)
			return false;
		return true;
	}
};
inline bool is_similar(const triangle &amp;u, const triangle &amp;v)
{
	return eq(u.x / v.x, u.y / v.y, u.z / v.z);
}
point pts[100]; int npt;
triangle tris[10000]; int ntri;
inline void build_triangles()
{
	ntri = 0;
	for (int i = 0; i &lt; npt; ++i)
	{
		for (int j = i + 1; j &lt; npt; ++j)
		{
			for (int k = j + 1; k &lt; npt; ++k)
			{
				triangle tri(pts[i], pts[j], pts[k]);
				if (tri.is_valid())
					tris[ntri++] = tri;
			}
		}
	}
}
inline int count_triangles()
{
	int max_similar = 0;
	for (int i = 0; i &lt; ntri; ++i)
	{
		int similar = 0;
		for (int j = i; j &lt; ntri; ++j)
			similar += is_similar(tris[i], tris[j]) ? 1 : 0;
		max_similar = max(max_similar, similar);
	}
	return max_similar;
}
int main()
{
	// freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
	while (scanf(&quot;%d&quot;, &amp;npt))
	{
		if (npt == 0)
			break;
		for (int i = 0; i &lt; npt; ++i)
			scanf(&quot;%d %d&quot;, &amp;pts[i].x, &amp;pts[i].y);
		sort(pts, pts + npt);
		npt = unique(pts, pts + npt) - pts;
		build_triangles();
		printf(&quot;%d\n&quot;, count_triangles());
	}
	return 0;
}</code></pre><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><div
style="margin-top:15px;" ><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><strong>原创文章，转载请注明来源：</strong><a
href="http://euyuil.com/3204/acm-icpc-2011-beijing-hou-yis-secret/" >http://euyuil.com/3204/acm-icpc-2011-beijing-hou-yis-secret/</a></p></div> ]]></content:encoded> <wfw:commentRss>http://euyuil.com/3204/acm-icpc-2011-beijing-hou-yis-secret/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>ACM/ICPC 2011 北京现场赛 Qin Shi Huang&#8217;s National Road Syst.</title><link>http://euyuil.com/3199/acm-icpc-2011-beijing-qin-shi-huangs-national-road-system/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=acm-icpc-2011-beijing-qin-shi-huangs-national-road-system</link> <comments>http://euyuil.com/3199/acm-icpc-2011-beijing-qin-shi-huangs-national-road-system/#comments</comments> <pubDate>Wed, 08 Feb 2012 04:08:06 +0000</pubDate> <dc:creator>EUYUIL</dc:creator> <category><![CDATA[无类可分]]></category> <category><![CDATA[ACM]]></category> <category><![CDATA[区域赛]]></category> <category><![CDATA[图论]]></category> <category><![CDATA[最小生成树]]></category> <category><![CDATA[次小生成树]]></category> <category><![CDATA[现场赛]]></category> <category><![CDATA[题解]]></category> <guid
isPermaLink="false">http://euyuil.com/?p=3199</guid> <description><![CDATA[类似于图论的次小生成树。现场赛过程中，在 WH 的提示下，Wideas 敲的这题。赛后 WH 回忆到，比赛时他想起暑假的时候郭炜说：“你们一定要懂次小生成树啊！”结果就想出了这题…… 首先生成图的最小生成树，然后，枚举任意两点 u, v: 如果边 (u, v) 就在最小生成树里，那么就算一下把 (u, v) 当成 magic road 时，［人口 / 其余路径长度］的值（即 A / B 的值）；如果边 (u, v) 不在最小生成树里，那么此时如果连接 u 和 v, 就会形成一个环，在环上找到除 (u, v) 外最大的一条边，删除之，再以 (u, v) 为 magic road, 计算 A / B 的值。记录下每次计算出来的值中的最大值，输出之。 我是用 Prim 写的最小生成树，因为这题是一个完全图，边数有点多。然后，我使用了一个二维数组来记录，最小生成树中，路径 u → v 上最长的边有多长。方法是每添加一个新顶点的时候，就判断所有已经添加到最小生成树中的顶点，到新添加的顶点的路径上最长的边的长度。具体内容在我的源代码的 82 到 89 [...]]]></description> <content:encoded><![CDATA[<p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">类似于图论的次小生成树。现场赛过程中，在 WH 的提示下，Wideas 敲的这题。赛后 WH 回忆到，比赛时他想起暑假的时候郭炜说：“你们一定要懂次小生成树啊！”结果就想出了这题……</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">首先生成图的最小生成树，然后，枚举任意两点 u, v: 如果边 (u, v) 就在最小生成树里，那么就算一下把 (u, v) 当成 magic road 时，［人口 / 其余路径长度］的值（即 A / B 的值）；如果边 (u, v) 不在最小生成树里，那么此时如果连接 u 和 v, 就会形成一个环，在环上找到除 (u, v) 外最大的一条边，删除之，再以 (u, v) 为 magic road, 计算 A / B 的值。记录下每次计算出来的值中的最大值，输出之。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><span
id="more-3199" ></span></p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">我是用 Prim 写的最小生成树，因为这题是一个完全图，边数有点多。然后，我使用了一个二维数组来记录，最小生成树中，路径 u → v 上最长的边有多长。方法是每添加一个新顶点的时候，就判断所有已经添加到最小生成树中的顶点，到新添加的顶点的路径上最长的边的长度。具体内容在我的源代码的 82 到 89 行中。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">源代码如下：</p><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;algorithm&gt;
#include &lt;cstring&gt;
#include &lt;cstdio&gt;
#include &lt;vector&gt;
#include &lt;queue&gt;
#include &lt;cmath&gt;
using namespace std;
const int N = 1000;
struct edge_t
{
	int u, v;
	inline edge_t() { }
	inline edge_t(int u, int v) : u(u), v(v) { }
};
double graph[N][N], max_edge[N][N];
int n, population[N], posx[N], posy[N];
class length_greater {
public:
	inline bool operator()(const edge_t &amp;a, const edge_t &amp;b) {
		return graph[a.u][a.v] &gt; graph[b.u][b.v];
	}
};
inline void init_and_input()
{
	memset(max_edge, 0, sizeof max_edge);
	memset(graph, 0, sizeof graph);
	scanf(&quot;%d&quot;, &amp;n);
	for (int i = 0; i &lt; n; ++i)
		scanf(&quot;%d %d %d&quot;, posx + i, posy + i, population + i);
	for (int i = 0; i &lt; n; ++i)
	{
		for (int j = 0; j &lt; i; ++j)
		{
			int dx = posx[j] - posx[i];
			int dy = posy[j] - posy[i];
			graph[i][j] = graph[j][i] = sqrt((double)(dx * dx + dy * dy));
		}
	}
}
inline double less_prim()
{
	priority_queue&lt;edge_t, vector&lt;edge_t&gt;, length_greater&gt; edges;
	vector&lt;bool&gt; intree(n, false);
	int last_node = 0; double result = 0;
	for (int i = 1; i &lt; n; ++i)
	{
		intree[last_node] = true;
		// For each edge from last_node.
		for (int j = 0; j &lt; n; ++j)
			if (!intree[j])
				edges.push(edge_t(last_node, j));
		// Get max valid edge.
		edge_t edge;
		do {
			edge = edges.top(); edges.pop();
		} while (intree[edge.u] &amp;&amp; intree[edge.v]);
		double current_length = graph[edge.u][edge.v];
		result += current_length;
		int intree_node, newly_node;
		if (intree[edge.u]) {
			intree_node = edge.u;
			newly_node = edge.v;
		} else {
			intree_node = edge.v;
			newly_node = edge.u;
		}
		for (int j = 0; j &lt; n; ++j)
		{
			if (intree[j])
			{
				double current_max = max(current_length, max_edge[j][intree_node]);
				max_edge[j][newly_node] = max_edge[newly_node][j] = current_max;
			}
		}
		last_node = newly_node;
	}
	return result;
}
int main()
{
	// freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
	int T;
	scanf(&quot;%d&quot;, &amp;T);
	while (T--)
	{
		init_and_input();
		double mst = less_prim();
		double max_ratio = 0.0f;
		for (int i = 0; i &lt; n; ++i)
		{
			for (int j = 0; j &lt; n; ++j)
			{
				if (i == j) continue;
				int pop = population[i] + population[j];
				double non_magic = mst - max_edge[i][j];
				double ratio = (double)pop / non_magic;
				max_ratio = max_ratio &gt; ratio ? max_ratio : ratio;
			}
		}
		printf(&quot;%0.2lf\n&quot;, max_ratio);
	}
	return 0;
}</code></pre><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><div
style="margin-top:15px;" ><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><strong>原创文章，转载请注明来源：</strong><a
href="http://euyuil.com/3199/acm-icpc-2011-beijing-qin-shi-huangs-national-road-system/" >http://euyuil.com/3199/acm-icpc-2011-beijing-qin-shi-huangs-national-road-system/</a></p></div> ]]></content:encoded> <wfw:commentRss>http://euyuil.com/3199/acm-icpc-2011-beijing-qin-shi-huangs-national-road-system/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>ACM/ICPC 2010 天津现场赛 I&#8217;m Telling the Truth 题解</title><link>http://euyuil.com/3195/acm-icpc-2010-tianjin-im-telling-the-truth/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=acm-icpc-2010-tianjin-im-telling-the-truth</link> <comments>http://euyuil.com/3195/acm-icpc-2010-tianjin-im-telling-the-truth/#comments</comments> <pubDate>Tue, 07 Feb 2012 06:11:26 +0000</pubDate> <dc:creator>EUYUIL</dc:creator> <category><![CDATA[无类可分]]></category> <category><![CDATA[ACM]]></category> <category><![CDATA[二分图匹配]]></category> <category><![CDATA[区域赛]]></category> <category><![CDATA[图论]]></category> <category><![CDATA[现场赛]]></category> <category><![CDATA[网络流]]></category> <guid
isPermaLink="false">http://euyuil.com/?p=3195</guid> <description><![CDATA[这道题的题意是，一些学生说出他们各自的排名范围（不存在并列），然后有的学生说谎了，结果就产生了矛盾。比如有 3 个学生分别都说自己的排名是 1 ~ 2 名，那么肯定至少有一个学生说谎。题目要求计算出最多有几个学生说了真话，并且把那些说真话的学生序号输出。如果有多种情况，输出字典序最高的那种。 数据范围，最多有 100 cases, 学生最多 60 名。排名的话，以区间 [x, y] 表示，其中 1 ≤ x ≤ y ≤ 100000. 开始看这个数据，想起队友 WH 说的，如果有那些 30 啊 60 啊之类的东西，就想想是不是动规，因为那些 30 或者 60 刚好是 32 位整型和 64 位整型能表示的东西。 然后我看到区间，而且范围还挺大，就不禁想到线段树。 后来还是没有想法。Google 了一下，发现前人居然是用二分图匹配来写的。感觉这还是有点勉强啊，而且出题者设计的数据也太容易让人想歪了。 源代码如下： #include &#60;set&#62; #include &#60;vector&#62; #include &#60;cstdio&#62; #include &#60;cstring&#62; #include &#60;algorithm&#62; using namespace std; [...]]]></description> <content:encoded><![CDATA[<p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这道题的题意是，一些学生说出他们各自的排名范围（不存在并列），然后有的学生说谎了，结果就产生了矛盾。比如有 3 个学生分别都说自己的排名是 1 ~ 2 名，那么肯定至少有一个学生说谎。题目要求计算出最多有几个学生说了真话，并且把那些说真话的学生序号输出。如果有多种情况，输出字典序最高的那种。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">数据范围，最多有 100 cases, 学生最多 60 名。排名的话，以区间 [x, y] 表示，其中 1 ≤ x ≤ y ≤ 100000.</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><span
id="more-3195" ></span></p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">开始看这个数据，想起队友 WH 说的，如果有那些 30 啊 60 啊之类的东西，就想想是不是动规，因为那些 30 或者 60 刚好是 32 位整型和 64 位整型能表示的东西。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">然后我看到区间，而且范围还挺大，就不禁想到线段树。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">后来还是没有想法。Google 了一下，发现前人居然是用二分图匹配来写的。感觉这还是有点勉强啊，而且出题者设计的数据也太容易让人想歪了。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">源代码如下：</p><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;set&gt;
#include &lt;vector&gt;
#include &lt;cstdio&gt;
#include &lt;cstring&gt;
#include &lt;algorithm&gt;
using namespace std;
typedef vector&lt;vector&lt;int&gt; &gt; graph_t;
typedef vector&lt;int&gt; int_array;
typedef set&lt;int&gt; int_set;
const int N = 111111; // Max rank.
const int M = 100; // Students.
graph_t graph;
int match_student[N];
int_set rank_occupied;
bool hungarian(int student)
{
	for (int i = 0; i &lt; graph[student].size(); ++i)
	{
		int rank = graph[student][i];
		if (rank_occupied.find(rank) != rank_occupied.end())
			continue; // If rank occupied this time.
		rank_occupied.insert(rank);
		if (match_student[rank] == -1 || // If the rank is not assigned.
			hungarian(match_student[rank])) // Or someone can go elsewhere.
		{
			match_student[rank] = student;
			return true;
		}
	}
	return false;
}
inline void init(int student_count)
{
	graph.clear();
	graph.resize(student_count + 1);
	memset(match_student, -1, sizeof match_student);
}
int main()
{
	// freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
	int T, n;
	scanf(&quot;%d&quot;, &amp;T);
	while (T--)
	{
		scanf(&quot;%d&quot;, &amp;n); init(n);
		for (int i = 0; i &lt; n; ++i)
		{
			int x, y;
			scanf(&quot;%d %d&quot;, &amp;x, &amp;y);
			for ( ; x &lt;= y; ++x)
				graph[i].push_back(x);
		}
		int result = 0;
		for (int i = n - 1; i &gt;= 0; --i)
		{
			rank_occupied.clear();
			if (hungarian(i))
				++result;
		}
		int_array scheme; scheme.reserve(M);
		for (int i = 0; i &lt; N; ++i)
			if (match_student[i] != -1)
				scheme.push_back(match_student[i]);
		sort(scheme.begin(), scheme.end());
		printf(&quot;%d\n&quot;, result);
		if (!scheme.empty())
			printf(&quot;%d&quot;, scheme[0] + 1);
		for (int i = 1; i &lt; scheme.size(); ++i)
			printf(&quot; %d&quot;, scheme[i] + 1);
		printf(&quot;\n&quot;);
	}
	return 0;
}</code></pre><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><div
style="margin-top:15px;" ><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><strong>原创文章，转载请注明来源：</strong><a
href="http://euyuil.com/3195/acm-icpc-2010-tianjin-im-telling-the-truth/" >http://euyuil.com/3195/acm-icpc-2010-tianjin-im-telling-the-truth/</a></p></div> ]]></content:encoded> <wfw:commentRss>http://euyuil.com/3195/acm-icpc-2010-tianjin-im-telling-the-truth/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>ACM/ICPC 2011 福州现场赛 Xiangqi 题解</title><link>http://euyuil.com/3190/acm-icpc-2011-fuzhou-xiangqi-solution/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=acm-icpc-2011-fuzhou-xiangqi-solution</link> <comments>http://euyuil.com/3190/acm-icpc-2011-fuzhou-xiangqi-solution/#comments</comments> <pubDate>Mon, 06 Feb 2012 17:48:24 +0000</pubDate> <dc:creator>EUYUIL</dc:creator> <category><![CDATA[无类可分]]></category> <category><![CDATA[ACM]]></category> <category><![CDATA[区域赛]]></category> <category><![CDATA[模拟]]></category> <category><![CDATA[现场赛]]></category> <category><![CDATA[题解]]></category> <guid
isPermaLink="false">http://euyuil.com/?p=3190</guid> <description><![CDATA[这道象棋模拟题其实还是比较简单的，但是写起来要注意的地方非常多。测试数据据说不太刁钻，比如那种黑方能够直接获胜的棋局（表现为一开始将帅之间就没有任何棋子而相对）是没有的。不过为了内心的宁静，我在代码里还是加上了这些特判内容。 赛后练习时提交了三次才 AC, 原因是判断红方马的时候不小心判断到了黑方 boss 的原来位置上（而正确的判断方法应该是黑方 boss 走一步之后的那个位置），后来检查了几遍才看出来。 这里面还有一些小技巧，就是可以专门写一个函数，判断两个棋子之间有多少个其它棋子，这样炮、车、帅就好复用了。其实这里面车的 behavior 和帅的基本上是一样的。 现场赛的时候是队长 Wideas 敲的，赛后他对我的教诲是，对于这种模拟题，数据范围并不是特别大，考点在于编程细心方面的，写起来就不要考虑太多执行效率上的问题了。嗯，所以这种题，应该怎么写爽，就怎么写。 #include &#60;cstdio&#62; #include &#60;cstring&#62; using namespace std; int board[20][20]; int bossx, bossy, red_boss; int redcnt, redx[10], redy[10]; char redtype[10]; const int dirx[4] = { -1, 0, 1, 0}; const int diry[4] = { 0, 1, 0, -1}; const int horx[8] = [...]]]></description> <content:encoded><![CDATA[<p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这道象棋模拟题其实还是比较简单的，但是写起来要注意的地方非常多。测试数据据说不太刁钻，比如那种黑方能够直接获胜的棋局（表现为一开始将帅之间就没有任何棋子而相对）是没有的。不过为了内心的宁静，我在代码里还是加上了这些特判内容。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">赛后练习时提交了三次才 AC, 原因是判断红方马的时候不小心判断到了黑方 boss 的原来位置上（而正确的判断方法应该是黑方 boss 走一步之后的那个位置），后来检查了几遍才看出来。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><span
id="more-3190" ></span></p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这里面还有一些小技巧，就是可以专门写一个函数，判断两个棋子之间有多少个其它棋子，这样炮、车、帅就好复用了。其实这里面车的 behavior 和帅的基本上是一样的。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">现场赛的时候是队长 Wideas 敲的，赛后他对我的教诲是，对于这种模拟题，数据范围并不是特别大，考点在于编程细心方面的，写起来就不要考虑太多执行效率上的问题了。嗯，所以这种题，应该怎么写爽，就怎么写。</p><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;cstdio&gt;
#include &lt;cstring&gt;
using namespace std;
int board[20][20];
int bossx, bossy, red_boss;
int redcnt, redx[10], redy[10];
char redtype[10];
const int dirx[4] = { -1,  0,  1,  0};
const int diry[4] = {  0,  1,  0, -1};
const int horx[8] = { -2, -2, -1,  1,  2,  2,  1, -1};
const int hory[8] = { -1,  1,  2,  2,  1, -1, -2, -2};
const int NONE  = 0;
const int RED   = 1;
const int BLACK = 2;
inline bool init_and_input()
{
	memset(board, 0, sizeof board);
	scanf(&quot;%d %d %d&quot;, &amp;redcnt, &amp;bossx, &amp;bossy);
	if (redcnt == 0 &amp;&amp; bossx == 0 &amp;&amp; bossy == 0)
		return false;
	char buf[8];
	for (int i = 0; i &lt; redcnt; ++i)
	{
		scanf(&quot;%s %d %d&quot;, buf, &amp;redx[i], &amp;redy[i]);
		redtype[i] = *buf; red_boss = -1;
		board[redx[i]][redy[i]] = RED;
		if (*buf == 'G')
			red_boss = i;
	}
	return true;
}
inline bool is_on_board(int x, int y)
{
	if (x &gt;= 1 &amp;&amp; x &lt;= 10 &amp;&amp; y &gt;= 1 &amp;&amp; y &lt;= 9)
		return true;
	return false;
}
inline bool is_in_palace(int x, int y)
{
	if (x &gt;= 1 &amp;&amp; x &lt;= 3 &amp;&amp; y &gt;= 4 &amp;&amp; y &lt;= 6)
		return true;
	if (x &gt;= 8 &amp;&amp; x &lt;= 10 &amp;&amp; y &gt;= 4 &amp;&amp; y &lt;= 6)
		return true;
	return false;
}
inline int count_between(int index, int x, int y)
{
	int delta = 0, result = 0;
	if (redx[index] == x)
	{
		if (y &gt; redy[index])
			delta = 1;
		else
			delta = -1;
		for (int i = redy[index] + delta; i != y; i += delta)
			if (board[x][i] != NONE)
				++result;
		return result;
	}
	else if (redy[index] == y)
	{
		if (x &gt; redx[index])
			delta = 1;
		else
			delta = -1;
		for (int i = redx[index] + delta; i != x; i += delta)
			if (board[i][y] != NONE)
				++result;
		return result;
	}
	return -1;
}
inline bool chariot_can_eat(int index, int x, int y)
{
	return count_between(index, x, y) == 0;
}
inline bool general_can_eat(int index, int x, int y)
{
	return chariot_can_eat(index, x, y);
}
inline bool cannon_can_eat(int index, int x, int y)
{
	return count_between(index, x, y) == 1;
}
inline bool horse_can_eat(int index, int x, int y)
{
	for (int i = 0; i &lt; 8; ++i)
	{
		int destx = redx[index] + horx[i];
		int desty = redy[index] + hory[i];
		int footx = redx[index] + dirx[i &gt;&gt; 1];
		int footy = redy[index] + diry[i &gt;&gt; 1];
		if (!is_on_board(destx, desty))
			continue;
		if (!is_on_board(footx, footy))
			continue;
		if (board[footx][footy] != NONE)
			continue;
		if (destx == x &amp;&amp; desty == y)
			return true;
	}
	return false;
}
inline bool can_eat(int index, int x, int y)
{
	switch (redtype[index])
	{
	case 'G':
		return general_can_eat(index, x, y);
	case 'R':
		return chariot_can_eat(index, x, y);
	case 'C':
		return cannon_can_eat(index, x, y);
	case 'H':
		return horse_can_eat(index, x, y);
	}
	return false;
}
int main()
{
	// freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
	while (init_and_input())
	{
		if (count_between(red_boss, bossx, bossy) == 0)
		{
			printf(&quot;NO\n&quot;);
			break;
		}
		bool result = true;
		for (int i = 0; i &lt; 4; ++i)
		{
			int x = bossx + dirx[i];
			int y = bossy + diry[i];
			if (!is_in_palace(x, y))
				continue;
			int before = board[x][y];
			board[x][y] = BLACK;
			bool eat = false;
			for (int j = 0; j &lt; redcnt; ++j)
			{
				if (board[redx[j]][redy[j]] != RED)
					continue;
				if (can_eat(j, x, y))
				{
					eat = true;
					break;
				}
			}
			if (!eat)
			{
				result = false;
				break;
			}
			board[x][y] = before;
		}
		if (result)
			printf(&quot;YES\n&quot;);
		else
			printf(&quot;NO\n&quot;);
	}
	return 0;
}</code></pre><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><div
style="margin-top:15px;" ><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><strong>原创文章，转载请注明来源：</strong><a
href="http://euyuil.com/3190/acm-icpc-2011-fuzhou-xiangqi-solution/" >http://euyuil.com/3190/acm-icpc-2011-fuzhou-xiangqi-solution/</a></p></div> ]]></content:encoded> <wfw:commentRss>http://euyuil.com/3190/acm-icpc-2011-fuzhou-xiangqi-solution/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>ACM/ICPC 2010 杭州现场赛 Rotational Painting 题解</title><link>http://euyuil.com/3186/acm-icpc-2010-hangzhou-rotational-painting/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=acm-icpc-2010-hangzhou-rotational-painting</link> <comments>http://euyuil.com/3186/acm-icpc-2010-hangzhou-rotational-painting/#comments</comments> <pubDate>Mon, 06 Feb 2012 09:03:09 +0000</pubDate> <dc:creator>EUYUIL</dc:creator> <category><![CDATA[无类可分]]></category> <category><![CDATA[ACM]]></category> <category><![CDATA[凸包]]></category> <category><![CDATA[区域赛]]></category> <category><![CDATA[垂线]]></category> <category><![CDATA[垂足]]></category> <category><![CDATA[多边形]]></category> <category><![CDATA[多边形重心]]></category> <category><![CDATA[数据生成器]]></category> <category><![CDATA[现场赛]]></category> <category><![CDATA[计算几何]]></category> <guid
isPermaLink="false">http://euyuil.com/?p=3186</guid> <description><![CDATA[不错的计算几何题。题目输入若干个简单多边形（允许存在凹多边形，但是多边形的边不会交叉），它们的质量是均匀的。要求计算每个多边形在水平线上有多少种稳定的摆放方式。其中一个比较特别的地方就是，如果重心和支撑线段所作的垂心与支撑线段的端点重合，视为不稳定的状态。具体原题的配图中说得很清楚，就不多说了。多边形的边数可能达到 50000 条。 思路应该是比较清晰的：首先求多边形的凸包，然后求多边形的重心；再枚举凸包上的每一条边，从重心向枚举的边作垂线；如果所作的垂线能够与边规范相交，那么这种情况是一种稳定情况。 思路确实很简单，但是写起来就有很多东西要写。比如凸包就是一个比较长的东西了，然后求重心又涉及到多边形的三角形分割啥的，还有垂线与边相交的判定也是有点麻烦的。 这道题我 WA 了一次，是因为我计算重心的时候，用的是凸包而不是原多边形。 本题源代码 #include &#60;cmath&#62; #include &#60;vector&#62; #include &#60;cstdio&#62; #include &#60;algorithm&#62; using namespace std; ///////////// // Numbers // ///////////// const double eps = 1e-6; inline int sgn(double a) { return a &#62; eps ? 1 : a &#60; -eps ? -1 : 0; } inline bool eq(double a, double [...]]]></description> <content:encoded><![CDATA[<p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">不错的计算几何题。题目输入若干个简单多边形（允许存在凹多边形，但是多边形的边不会交叉），它们的质量是均匀的。要求计算每个多边形在水平线上有多少种稳定的摆放方式。其中一个比较特别的地方就是，如果重心和支撑线段所作的垂心与支撑线段的端点重合，视为不稳定的状态。具体原题的配图中说得很清楚，就不多说了。多边形的边数可能达到 50000 条。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">思路应该是比较清晰的：首先求多边形的凸包，然后求多边形的重心；再枚举凸包上的每一条边，从重心向枚举的边作垂线；如果所作的垂线能够与边规范相交，那么这种情况是一种稳定情况。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><span
id="more-3186" ></span></p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">思路确实很简单，但是写起来就有很多东西要写。比如凸包就是一个比较长的东西了，然后求重心又涉及到多边形的三角形分割啥的，还有垂线与边相交的判定也是有点麻烦的。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这道题我 WA 了一次，是因为我计算重心的时候，用的是凸包而不是原多边形。</p><h2>本题源代码</h2><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;cmath&gt;
#include &lt;vector&gt;
#include &lt;cstdio&gt;
#include &lt;algorithm&gt;
using namespace std;
/////////////
// Numbers //
/////////////
const double eps = 1e-6;
inline int sgn(double a)
{
	return a &gt; eps ? 1 : a &lt; -eps ? -1 : 0;
}
inline bool eq(double a, double b)
{
	return !sgn(a - b);
}
inline bool lt(double a, double b)
{
	return sgn(a - b) &lt; 0;
}
inline bool gt(double a, double b)
{
	return sgn(a - b) &gt; 0;
}
////////////
// Points //
////////////
struct point
{
	double x, y;
	inline point() : x(0.0), y(0.0) { }
	inline point(double x, double y) : x(x), y(y) { }
	inline point operator+(const point &amp;b) const {
		return point(x + b.x, y + b.y);
	}
	inline point operator-(const point &amp;b) const {
		return point(x - b.x, y - b.y);
	}
	inline point operator*(double k) const {
		return point(x * k, y * k);
	}
	inline point operator/(double k) const {
		return point(x / k, y / k);
	}
	inline point &amp;operator+=(const point &amp;b) {
		x += b.x; y += b.y; return *this;
	}
	inline point &amp;operator-=(const point &amp;b) {
		x -= b.x; y -= b.y; return *this;
	}
	inline point &amp;operator*=(double k) {
		x *= k; y *= k; return *this;
	}
	inline point &amp;operator/=(double k) {
		x /= k; y /= k; return *this;
	}
	inline bool operator==(const point &amp;b) const {
		return eq(x, b.x) &amp;&amp; eq(y, b.y);
	}
	inline double magsqr() const {
		return x * x + y * y;
	}
};
inline double cross(const point &amp;a, const point &amp;b) {
	return a.x * b.y - a.y * b.x;
}
inline double dot(const point &amp;a, const point &amp;b) {
	return a.x * b.x + a.y * b.y;
}
inline double ccw(const point &amp;p, const point &amp;a, const point &amp;b) {
	return cross(a - p, b - p);
}
///////////
// Lines //
///////////
struct line
{
	point a, b;
	inline line(const point &amp;a, const point &amp;b) : a(a), b(b) { }
	inline point vec() const {
		return b - a;
	}
};
inline point inpll(const line &amp;la, const line &amp;lb)
{
	double u = cross(la.vec(), point(lb.b - la.b));
	double v = cross(la.vec(), point(lb.a - la.b));
	return (lb.b * v - lb.a * u) / (v - u);
}
inline int relpl(const point &amp;p, const line &amp;l)
{
	return sgn(cross(p - l.a, l.vec())); // 0: on; -1: .|; 1: |..
}
inline int relps(const point &amp;p, const line &amp;s)
{
	int rp = relpl(p, s);
	if (rp) return rp * 3; // -3: .|; 3: |..
	point psa = s.a - p, psb = s.b - p;
	int r = sgn(dot(psa, psb));
	if (r &lt; 0) return 0; // The point is on the segment between end-points.
	if (r == 0) return 1; // The point is at either end-point.
	return 2; // The point is on the line s.
}
inline point plupl(const point &amp;p, const line &amp;l)
{
	point u = l.vec(), v = p - l.a;
	return l.a + u * dot(u, v) / u.magsqr();
}
//////////////
// Polygons //
//////////////
typedef vector&lt;point&gt; polygon;
inline point tricore(const point &amp;a, const point &amp;b, const point &amp;c)
{
	return point((a.x + b.x + c.x) / 3.0, (a.y + b.y + c.y) / 3.0);
}
inline point polycore(const polygon &amp;poly)
{
	point core(0.0, 0.0);
	double mass = 0.0;
	for (int i = 2; i &lt; poly.size(); ++i)
	{
		point c = tricore(poly[0], poly[i - 1], poly[i]);
		double m = ccw(poly[0], poly[i - 1], poly[i]);
		core += (c *= m);
		mass += m;
	}
	return core /= mass;
}
struct graham_scan
{
	vector&lt;bool&gt; instack;
	vector&lt;int&gt; indices;
	inline static bool lessthan(const point &amp;a, const point &amp;b)
	{
		if (eq(a.y, b.y))
			return lt(a.x, b.x);
		return lt(a.y, b.y);
	}
	inline void scan(const polygon &amp;po, int begin, int end, int delta)
	{
		for (int i = begin; i != end; i += delta)
		{
			if (instack[i]) continue;
			while (indices.size() &gt;= 2)
			{
				const point &amp;a = po[indices.back()];
				const point &amp;p = po[indices[indices.size() - 2]];
				if (sgn(ccw(p, a, po[i])) &lt;= 0) {
					instack[indices.back()] = false; indices.pop_back();
				} else break;
			}
			instack[i] = true; indices.push_back(i);
		}
	}
	inline void solve_indices(polygon &amp;poly) // Incoming poly will be changed.
	{
		instack.clear(); instack.resize(poly.size(), false);
		indices.clear(); indices.reserve(poly.size() + 1);
		sort(poly.begin(), poly.end(), lessthan);
		poly.resize(unique(poly.begin(), poly.end()) - poly.begin());
		indices.push_back(0);
		scan(poly, 1, poly.size(), 1);
		scan(poly, poly.size() - 1, -1, -1);
		indices.pop_back();
	}
	inline polygon polygon_from_indices(const polygon &amp;original)
	{
		polygon result; result.reserve(indices.size());
		for (int i = 0; i &lt; indices.size(); ++i)
			result.push_back(original[indices[i]]);
		return result;
	}
};
graham_scan graham;
inline int stable_side_count(const polygon &amp;original)
{
	polygon sorted = original;
	graham.solve_indices(sorted);
	polygon convex = graham.polygon_from_indices(sorted);
	int result = 0;
	point core = polycore(original);
	for (int i = 0; i &lt; convex.size(); ++i)
	{
		int j = (i + 1) % convex.size();
		line edge(convex[i], convex[j]);
		point plumb = plupl(core, edge);
		if (relps(plumb, edge) == 0)
			++result;
	}
	return result;
}
int main()
{
	// freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
	int T, n;
	scanf(&quot;%d&quot;, &amp;T);
	while (T--)
	{
		polygon poly;
		scanf(&quot;%d&quot;, &amp;n);
		poly.reserve(n);
		while (n--)
		{
			double x, y;
			scanf(&quot;%lf %lf&quot;, &amp;x, &amp;y);
			poly.push_back(point(x, y));
		}
		printf(&quot;%d\n&quot;, stable_side_count(poly));
	}
	return 0;
}</code></pre><h2>数据生成器源代码</h2><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;iostream&gt;
#include &lt;cstdlib&gt;
#include &lt;cstdio&gt;
#include &lt;ctime&gt;
using namespace std;
int main()
{
	freopen(&quot;input.txt&quot;, &quot;w&quot;, stdout);
	srand(clock());
	int t = 1000;
	cout &lt;&lt; t &lt;&lt; endl &lt;&lt; endl;
	while (t--)
	{
		int n = rand() % 10 + 3;
		cout &lt;&lt; n &lt;&lt; endl &lt;&lt; endl;
		while (n--)
			cout &lt;&lt; rand() % 100 &lt;&lt; ' ' &lt;&lt; rand() % 100 &lt;&lt; endl;
		cout &lt;&lt; endl &lt;&lt; endl;
	}
	return 0;
}</code></pre><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><div
style="margin-top:15px;" ><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><strong>原创文章，转载请注明来源：</strong><a
href="http://euyuil.com/3186/acm-icpc-2010-hangzhou-rotational-painting/" >http://euyuil.com/3186/acm-icpc-2010-hangzhou-rotational-painting/</a></p></div> ]]></content:encoded> <wfw:commentRss>http://euyuil.com/3186/acm-icpc-2010-hangzhou-rotational-painting/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>ACM/ICPC 2009 宁波现场赛 Open-air Shopping Malls</title><link>http://euyuil.com/3129/acm-icpc-2009-ningbo-open-air-shopping-malls/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=acm-icpc-2009-ningbo-open-air-shopping-malls</link> <comments>http://euyuil.com/3129/acm-icpc-2009-ningbo-open-air-shopping-malls/#comments</comments> <pubDate>Sun, 05 Feb 2012 16:39:25 +0000</pubDate> <dc:creator>EUYUIL</dc:creator> <category><![CDATA[无类可分]]></category> <category><![CDATA[ACM]]></category> <category><![CDATA[两圆相交]]></category> <category><![CDATA[二分]]></category> <category><![CDATA[分治]]></category> <category><![CDATA[区域赛]]></category> <category><![CDATA[数据生成器]]></category> <category><![CDATA[现场赛]]></category> <category><![CDATA[相交圆面积]]></category> <category><![CDATA[计算几何]]></category> <category><![CDATA[题解]]></category> <guid
isPermaLink="false">http://euyuil.com/?p=3129</guid> <description><![CDATA[这道题目是一道不错的计算几何题，题意是在一个平面上，有若干个圆（题目中称为商场）。然后需要以这些圆中的某一个圆的圆心为圆心画一个圆（题目中称为伞），使得新画的这个圆能够覆盖任何一个其它的圆的至少一半的面积。求这个圆的最小半径。 这道题的思路是，枚举每一个圆的圆心，然后以它为圆心画圆。用二分法处理半径，每枚举一个半径就尝试看能不能满足覆盖条件。然后找到最短的半径就行了。 这道题有至多 10 个 cases, 至多 20 个圆。圆心的坐标范围是 [-10000, 10000], 半径范围是 [1, 2000], 输入数据都是整数。输出要求精确到 1e-4 这样。 这题我尝试了很多次才 AC. 需要注意的问题是： 计算几何中如果用浮点一定要看准条件，尽量用 double. 如果数据到了 1e4 这种数量级，那么小数点要是表示到 4 位还是很有压力了。 这个坐标范围是 -10000 到 10000, 加上半径可以到 2000 这个条件，整个平面中可能产生的长度就可能达到 [latex]4000 + 10000 \sqrt{2}[/latex] 之多。一开始我以为令 [latex]\infty = 11111.0[/latex] 都已经便宜它了，后来 WA 才知道，唉。 还有那个 eps 也是要设得小一点，设置成 1e-5 都可能四舍五入错误的。其实设小一点时间完全够的。 我本来居然以为两圆如果是包含关系可以直接 pass, 后来 WA 了几次才发现其实如果是商场把伞给包了就跪了。 [...]]]></description> <content:encoded><![CDATA[<p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这道题目是一道不错的计算几何题，题意是在一个平面上，有若干个圆（题目中称为<strong>商场</strong>）。然后需要以<strong>这些圆中的某一个圆的圆心</strong>为圆心画一个圆（题目中称为<strong>伞</strong>），使得新画的这个圆能够覆盖任何一个其它的圆的至少一半的面积。求这个圆的最小半径。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这道题的思路是，枚举每一个圆的圆心，然后以它为圆心画圆。用二分法处理半径，每枚举一个半径就尝试看能不能满足覆盖条件。然后找到最短的半径就行了。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这道题有至多 10 个 cases, 至多 20 个圆。圆心的坐标范围是 [-10000, 10000], 半径范围是 [1, 2000], 输入数据都是整数。输出要求精确到 <span
style="font-family: 'courier new', courier;" >1e-4</span> 这样。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><span
id="more-3129" ></span></p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这题我尝试了很多次才 AC. 需要注意的问题是：</p><ul><li>计算几何中如果用浮点一定要看准条件，尽量用 <span
style="font-family: 'courier new', courier;" >double</span>. 如果数据到了 <span
style="font-family: 'courier new', courier;" >1e4</span> 这种数量级，那么小数点要是表示到 4 位还是很有压力了。</li><li>这个坐标范围是 -10000 到 10000, 加上半径可以到 2000 这个条件，整个平面中可能产生的长度就可能达到 [latex]4000 + 10000 \sqrt{2}[/latex] 之多。一开始我以为令 [latex]\infty = 11111.0[/latex] 都已经便宜它了，后来 WA 才知道，唉。</li><li>还有那个 <span
style="font-family: 'courier new', courier;" >eps</span> 也是要设得小一点，设置成 <span
style="font-family: 'courier new', courier;" >1e-5</span> 都可能四舍五入错误的。其实设小一点时间完全够的。</li><li>我本来居然以为两圆如果是包含关系可以直接 pass, 后来 WA 了几次才发现其实如果是商场把伞给包了就跪了。</li></ul><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">还有就是有的时候计算几何也确实容易莫名其妙地跪，比如以前似乎 POJ 如果输出 <span
style="font-family: 'courier new', courier;" >double</span> 用 <span
style="font-family: 'courier new', courier;" >%lf</span> 就不行（现在不知道可以了没有），用 <span
style="font-family: 'courier new', courier;" >%f</span> 才可以。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">在训练计算几何题目的时候使用数据生成器确实不错，从网上搜索标程，然后生成大量的数据，分别用标程和自己的程序来跑一跑，用专门的比较软件（比如 KDiff）比较一下，确实能够发现问题。</p><h2>本题源代码</h2><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;cmath&gt;
#include &lt;cstdio&gt;
#include &lt;vector&gt;
using namespace std;
const double eps = 1e-9;
const double pi = acos(-1.0);
const double inf = 1e18;
struct point_t
{
	double x, y;
	inline point_t(double a, double b) : x(a), y(b) { }
	inline point_t operator-(const point_t &amp;b) const {
		return point_t(x - b.x, y - b.y);
	}
	inline double magsqr() const {
		return x * x + y * y;
	}
	inline double mag() const {
		return sqrt(magsqr());
	}
};
struct circle_t
{
	point_t center;
	double radius;
	inline circle_t(const point_t &amp;c, double r) : center(c), radius(r) { }
};
inline int ccrel(const circle_t &amp;a, const circle_t &amp;b)
{
	double d = (b.center - a.center).mag();
	double p = a.radius + b.radius;
	double s = abs(a.radius - b.radius);
	if (p &lt;= d) return -1; // Outer.
	if (d &lt;= s) return 1; // Inner.
	return 0; // Coincide.
}
inline double cirarea(double radius)
{
	return pi * radius * radius;
}
inline double sectarea(double radius, double theta)
{
	return theta / (2.0 * pi) * cirarea(radius);
}
inline double triarea(double a, double b, double c)
{
	double m = (a + b + c) / 2.0;
	return sqrt(m * (m - a) * (m - b) * (m - c));
}
inline double ccarea(const circle_t &amp;a, const circle_t &amp;b)
{
	//*
	int rel = ccrel(a, b);
	if (rel &lt; 0) return 0.0f;
	if (rel &gt; 0) {
		if (a.radius &lt; b.radius)
			return cirarea(a.radius);
		return cirarea(b.radius);
	}
	//*/
	// Otherwise, two circles must coincide.
	double d = (b.center - a.center).mag();
	double d2 = d * d;
	double r2 = a.radius * a.radius;
	double R2 = b.radius * b.radius;
	double cosa = (r2 + d2 - R2) / (2.0 * a.radius * d);
	double cosb = (R2 + d2 - r2) / (2.0 * b.radius * d);
	double secta = sectarea(a.radius, 2.0 * acos(cosa));
	double sectb = sectarea(b.radius, 2.0 * acos(cosb));
	double quad = 2.0 * triarea(d, a.radius, b.radius);
	return secta + sectb - quad;
}
inline bool is_available(
	const circle_t &amp;umbrella, const vector&lt;circle_t&gt; &amp;malls)
{
	for (int i = 0; i &lt; malls.size(); ++i)
	{
		int rel = ccrel(umbrella, malls[i]);
		if (rel &lt; 0) return false;
		double coincide = ccarea(umbrella, malls[i]);
		double halfarea = cirarea(malls[i].radius) / 2.0;
		if (coincide &gt;= halfarea)
			continue;
		else
			return false;
	}
	return true;
}
int main()
{
	// freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
	int T, n;
	vector&lt;circle_t&gt; malls;
	scanf(&quot;%d&quot;, &amp;T);
	while (T--)
	{
		scanf(&quot;%d&quot;, &amp;n);
		malls.clear();
		malls.reserve(20);
		while (n--)
		{
			double x, y, r;
			scanf(&quot;%lf %lf %lf&quot;, &amp;x, &amp;y, &amp;r);
			malls.push_back(circle_t(point_t(x, y), r));
		}
		double result = inf;
		for (int i = 0; i &lt; malls.size(); ++i)
		{
			double left = 0.0f, right = inf;
			circle_t umbrella(malls[i].center, inf / 2.0);
			while (right - left &gt;= eps)
			{
				if (is_available(umbrella, malls))
					right = umbrella.radius;
				else
					left = umbrella.radius;
				umbrella.radius = (right + left) / 2.0;
			}
			if (umbrella.radius &lt; result)
				result = umbrella.radius;
		}
		printf(&quot;%.4lf\n&quot;, result);
	}
	return 0;
}</code></pre><h2>数据生成器源代码</h2><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;iostream&gt;
#include &lt;cstdlib&gt;
#include &lt;cstdio&gt;
#include &lt;ctime&gt;
using namespace std;
inline int coord()
{
	// return rand() % 20001 - 10000;
	return rand() % 41 - 20;
}
inline int radius()
{
	// return rand() % 2000 + 1;
	return rand() % 20 + 1;
}
int main()
{
	freopen(&quot;input.txt&quot;, &quot;w&quot;, stdout);
	srand(clock()); int t = 10000;
	cout &lt;&lt; t &lt;&lt; endl &lt;&lt; endl;
	for (int i = 0; i &lt; t; ++i)
	{
		int x = rand() % 20 + 1;
		cout &lt;&lt; x &lt;&lt; endl;
		for (int j = 0; j &lt; x; ++j)
			cout &lt;&lt; coord() &lt;&lt; ' ' &lt;&lt; coord() &lt;&lt; ' ' &lt;&lt; radius() &lt;&lt; endl;
		cout &lt;&lt; endl;
	}
}</code></pre><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><div
style="margin-top:15px;" ><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><strong>原创文章，转载请注明来源：</strong><a
href="http://euyuil.com/3129/acm-icpc-2009-ningbo-open-air-shopping-malls/" >http://euyuil.com/3129/acm-icpc-2009-ningbo-open-air-shopping-malls/</a></p></div> ]]></content:encoded> <wfw:commentRss>http://euyuil.com/3129/acm-icpc-2009-ningbo-open-air-shopping-malls/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>ACM/ICPC 2010 哈尔滨现场赛 Seaside 题解</title><link>http://euyuil.com/3120/acm-icpc-2010-harbin-seaside-solution/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=acm-icpc-2010-harbin-seaside-solution</link> <comments>http://euyuil.com/3120/acm-icpc-2010-harbin-seaside-solution/#comments</comments> <pubDate>Sun, 05 Feb 2012 12:54:56 +0000</pubDate> <dc:creator>EUYUIL</dc:creator> <category><![CDATA[无类可分]]></category> <category><![CDATA[ACM]]></category> <category><![CDATA[区域赛]]></category> <category><![CDATA[图论]]></category> <category><![CDATA[最短路]]></category> <category><![CDATA[有向图]]></category> <category><![CDATA[模板题]]></category> <category><![CDATA[水题]]></category> <category><![CDATA[现场赛]]></category> <category><![CDATA[题解]]></category> <guid
isPermaLink="false">http://euyuil.com/?p=3120</guid> <description><![CDATA[这道题是一道水的模板题，就是求个单源最短路。而且一开始我还想多了，还以为有负权环，结果居然没有。所以整道题就水了。SPFA 水过，唯一与模板不同的地方，就是它里面的节点有一个属性，叫做“是否是海滨城市”。求得单源最短路之后，要把所有的海滨城市的结果进行比较，取其中距离最短的那个。 代码如下： #include &#60;queue&#62; #include &#60;cstdio&#62; #include &#60;climits&#62; #include &#60;cstring&#62; using namespace std; const int N = 15; const int M = 155; const int inf = INT_MAX &#62;&#62; 1; struct glist { int we[M], fe[N], ne[M], he[M], m, n; bool seaside[N]; inline void reset(int graph_size = 0) { memset(fe, -1, sizeof fe); memset(seaside, [...]]]></description> <content:encoded><![CDATA[<p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这道题是一道水的模板题，就是求个单源最短路。而且一开始我还想多了，还以为有负权环，结果居然没有。所以整道题就水了。SPFA 水过，唯一与模板不同的地方，就是它里面的节点有一个属性，叫做“是否是海滨城市”。求得单源最短路之后，要把所有的海滨城市的结果进行比较，取其中距离最短的那个。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><span
id="more-3120" ></span></p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">代码如下：</p><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;queue&gt;
#include &lt;cstdio&gt;
#include &lt;climits&gt;
#include &lt;cstring&gt;
using namespace std;
const int N = 15;
const int M = 155;
const int inf = INT_MAX &gt;&gt; 1;
struct glist
{
	int we[M], fe[N], ne[M], he[M], m, n;
	bool seaside[N];
	inline void reset(int graph_size = 0) {
		memset(fe, -1, sizeof fe);
		memset(seaside, false, sizeof seaside);
		m = 0; n = graph_size;
	}
	inline void insert(int u, int v, int weight) {
		we[m] = weight;
		ne[m] = fe[u];
		he[m] = v;
		fe[u] = m++;
	}
};
struct spfa
{
	int dist[N]; bool inqu[N];
	inline void reset() {
		for (int i = 0; i &lt; N; ++i)
			dist[i] = inf;
		memset(inqu, false, sizeof inqu);
	}
	inline void solve(const glist &amp;g, int start)
	{
		queue&lt;int&gt; qu;
		qu.push(start); inqu[start] = true;
		dist[start] = 0;
		while (!qu.empty())
		{
			int u = qu.front();
			qu.pop(); inqu[u] = false;
			for (int e = g.fe[u]; e != -1; e = g.ne[e])
			{
				int v = g.he[e];
				int d = dist[u] + g.we[e];
				if (d &lt; dist[v])
				{
					dist[v] = d;
					if (!inqu[v]) {
						qu.push(v); inqu[v] = true;
					}
				}
			}
		}
	}
};
glist graph;
spfa shortest_path;
int main()
{
	// freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
	while (scanf(&quot;%d&quot;, &amp;graph.n) != EOF)
	{
		graph.reset(graph.n);
		for (int i = 0; i &lt; graph.n; ++i)
		{
			int m, p;
			scanf(&quot;%d %d&quot;, &amp;m, &amp;p);
			if (p == 0)
				graph.seaside[i] = false;
			else
				graph.seaside[i] = true;
			for (int j = 0; j &lt; m; ++j)
			{
				int s, l;
				scanf(&quot;%d %d&quot;, &amp;s, &amp;l);
				graph.insert(i, s, l);
			}
		}
		shortest_path.reset();
		shortest_path.solve(graph, 0);
		int result = inf;
		for (int i = 0; i &lt; graph.n; ++i)
			if (graph.seaside[i] &amp;&amp; shortest_path.dist[i] &lt; result)
				result = shortest_path.dist[i];
		printf(&quot;%d\n&quot;, result);
	}
	return 0;
}</code></pre><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><div
style="margin-top:15px;" ><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><strong>原创文章，转载请注明来源：</strong><a
href="http://euyuil.com/3120/acm-icpc-2010-harbin-seaside-solution/" >http://euyuil.com/3120/acm-icpc-2010-harbin-seaside-solution/</a></p></div> ]]></content:encoded> <wfw:commentRss>http://euyuil.com/3120/acm-icpc-2010-harbin-seaside-solution/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>ACM/ICPC 2010 天津现场赛 Building Roads 题解</title><link>http://euyuil.com/3114/acm-icpc-2010-tianjin-building-roads-solution/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=acm-icpc-2010-tianjin-building-roads-solution</link> <comments>http://euyuil.com/3114/acm-icpc-2010-tianjin-building-roads-solution/#comments</comments> <pubDate>Sun, 05 Feb 2012 10:35:59 +0000</pubDate> <dc:creator>EUYUIL</dc:creator> <category><![CDATA[无类可分]]></category> <category><![CDATA[ACM]]></category> <category><![CDATA[区域赛]]></category> <category><![CDATA[图论]]></category> <category><![CDATA[数据生成器]]></category> <category><![CDATA[无根树]]></category> <category><![CDATA[树]]></category> <category><![CDATA[现场赛]]></category> <category><![CDATA[题解]]></category> <guid
isPermaLink="false">http://euyuil.com/?p=3114</guid> <description><![CDATA[这道题是一道不错的图论题。其题意是这样的，在给出的一棵无根树中，拆掉其中的一条边（此时原图会变成两棵树），然后保持这条边的长度不变，用这条边将两棵树连接起来。（似乎拆掉之后，如果有必要，还可以连回原来的地方）。然后找到一种拆法，使得进行完这个过程后，整棵树的直径是最短的。题目求的就是这最短的直径是多少。 一开始不太有思路，后来 Google 到一篇文章，大致说了一下这道题和树的直径和半径有关，并且是枚举那条要拆的边。[ALP'10] 然后终于想通：拆掉一条边，之后分别求产生的两棵树的直径、中心和半径。再将两棵树的中心以刚才被拆的边相连，得到的结果就是拆这条边能够得到的最优解。假设拆掉的边的长度为 L, 那两棵树的直径和半径分别为 D1, D2, R1, R2, 那么，得到的结果这棵树的直径是 max{D1, D2, R1 + R2 + L}. 这道题的数据规模比较大，有 10 个 cases, 每个 case 至多能有 2500 个节点。使用这种方法似乎复杂度有 O(n2) 之大，我自己写了一个数据生成器，测试了最极端的数据，也到了将近 30 秒才出解。但是我提交到了 OJ 上，还是过了。可能数据没有想象的那么夸张吧。 本题源代码 #include &#60;queue&#62; #include &#60;cstdio&#62; #include &#60;climits&#62; #include &#60;utility&#62; #include &#60;cstring&#62; using namespace std; const int N = 2555; struct glist [...]]]></description> <content:encoded><![CDATA[<p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这道题是一道不错的图论题。其题意是这样的，在给出的一棵无根树中，拆掉其中的一条边（此时原图会变成两棵树），然后保持这条边的长度不变，用这条边将两棵树连接起来。（似乎拆掉之后，如果有必要，还可以连回原来的地方）。然后找到一种拆法，使得进行完这个过程后，整棵树的<strong>直径</strong>是最短的。题目求的就是这最短的直径是多少。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">一开始不太有思路，后来 Google 到一篇文章，大致说了一下这道题和树的直径和半径有关，并且是枚举那条要拆的边。<sup><a
href="#alp10"  title="alpc32:《天津站B题 Building Roads》" >[ALP'10]</a></sup></p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">然后终于想通：拆掉一条边，之后分别求产生的两棵树的直径、中心和半径。再将两棵树的中心以刚才被拆的边相连，得到的结果就是拆这条边能够得到的最优解。假设拆掉的边的长度为 L, 那两棵树的直径和半径分别为 D1, D2, R1, R2, 那么，得到的结果这棵树的直径是 max{D1, D2, R1 + R2 + L}.</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><span
id="more-3114" ></span></p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这道题的数据规模比较大，有 10 个 cases, 每个 case 至多能有 2500 个节点。使用这种方法似乎复杂度有 O(n<sup>2</sup>) 之大，我自己写了一个数据生成器，测试了最极端的数据，也到了将近 30 秒才出解。但是我提交到了 OJ 上，还是过了。可能数据没有想象的那么夸张吧。</p><h2>本题源代码</h2><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;queue&gt;
#include &lt;cstdio&gt;
#include &lt;climits&gt;
#include &lt;utility&gt;
#include &lt;cstring&gt;
using namespace std;
const int N = 2555;
struct glist
{
	int va[N &lt;&lt; 1]; // Edge weight value.
	int ne[N &lt;&lt; 1]; // Next edge of edge.
	int he[N &lt;&lt; 1]; // Head node of edge.
	int fe[N]; // First edge of node.
	int n; // Number of nodes, managed manually.
	int m; // Number of edges, managed by insert().
	int dis; // Disabled edge.
	inline void reset() {
		memset(fe, -1, sizeof fe);
		n = 0; m = 0; dis = -1;
	}
	inline void insert_single(int u, int v, int value) {
		va[m] = value;
		ne[m] = fe[u];
		he[m] = v;
		fe[u] = m++;
	}
	inline void insert(int u, int v, int value) {
		insert_single(u, v, value);
		insert_single(v, u, value);
	}
	inline static int reversed_edge(int e) {
		return e ^ 1;
	}
	inline int tail_vertex(int e) const {
		return he[reversed_edge(e)];
	}
	inline bool is_disabled_edge(int e) const {
		if (e == dis || e == reversed_edge(dis))
			return true;
		return false;
	}
};
struct tree_diameter
{
	int v1, v2, dist, prev[N];
	bool vst[N];
	inline void reset() {
		v1 = v2 = -1;
		dist = 0;
		memset(prev, -1, sizeof prev);
	}
	inline void find_max(const glist &amp;g, int u, int &amp;v, int &amp;dist)
	{
		v = u; dist = 0;
		queue&lt;pair&lt;int, int&gt; &gt; qu;
		qu.push(make_pair(u, 0));
		memset(vst, false, sizeof vst);
		vst[u] = true;
		while (!qu.empty())
		{
			int x = qu.front().first;
			int d = qu.front().second;
			qu.pop();
			if (d &gt; dist)
			{
				v = x;
				dist = d;
			}
			for (int e = g.fe[x]; e != -1; e = g.ne[e])
			{
				if (g.is_disabled_edge(e))
					continue;
				int y = g.he[e];
				if (vst[y])
					continue;
				vst[y] = true;
				int w = g.va[e];
				qu.push(make_pair(y, d + w));
				prev[y] = glist::reversed_edge(e);
			}
		}
	}
	inline void solve(const glist &amp;g, int u = 0) {
		find_max(g, u, v1, dist);
		find_max(g, v1, v2, dist);
	}
};
struct tree_radius
{
	int v, dist;
	inline void reset() {
		v = -1; dist = 0;
	}
	inline void solve(const glist &amp;g, const tree_diameter &amp;diam)
	{
		int x = diam.v2, y = -1; v = diam.v2;
		for (int e = diam.prev[x]; e != -1; e = diam.prev[y])
		{
			if (g.is_disabled_edge(e))
				continue;
			y = g.he[e];
			dist += g.va[e];
			if ((dist &lt;&lt; 1) &gt;= diam.dist)
			{
				int dist2 = diam.dist - (dist - g.va[e]);
				if (dist &lt; dist2) {
					v = y;
				} else {
					v = x;
					dist = dist2;
				}
				return;
			}
			x = y;
		}
	}
};
glist graph;
tree_diameter diameter;
tree_radius radius;
int main()
{
	// freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
	// freopen(&quot;output.txt&quot;, &quot;w&quot;, stdout);
	int T, result;
	scanf(&quot;%d&quot;, &amp;T);
	for (int i = 1; i &lt;= T; ++i)
	{
		graph.reset();
		scanf(&quot;%d&quot;, &amp;graph.n);
		result = INT_MAX;
		int u, v, w;
		for (int j = 1; j &lt; graph.n; ++j)
		{
			scanf(&quot;%d %d %d&quot;, &amp;u, &amp;v, &amp;w);
			graph.insert(u, v, w);
		}
		int r1, r2, d1, d2, l;
		for (int e = 0; e &lt; graph.m; e += 2)
		{
			v = graph.he[e];
			u = graph.tail_vertex(e);
			graph.dis = e;
			l = graph.va[e];
			diameter.reset();
			diameter.solve(graph, u);
			radius.reset();
			radius.solve(graph, diameter);
			d1 = diameter.dist;
			r1 = radius.dist;
			diameter.reset();
			diameter.solve(graph, v);
			radius.reset();
			radius.solve(graph, diameter);
			d2 = diameter.dist;
			r2 = radius.dist;
			int t = r1 + r2 + l;
			if (t &lt; d1) t = d1;
			if (t &lt; d2) t = d2;
			if (t &lt; result) result = t;
		}
		printf(&quot;Case %d: %d\n&quot;, i, result);
	}
	return 0;
}</code></pre><h2>自己写的极端数据生成器</h2><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;ctime&gt;
#include &lt;cstdio&gt;
#include &lt;cstdlib&gt;
using namespace std;
int main()
{
	freopen(&quot;input.txt&quot;, &quot;w&quot;, stdout);
	srand(clock());
	printf(&quot;10\n\n&quot;); // 10 test cases.
	for (int i = 0; i &lt; 10; ++i)
	{
		printf(&quot;2500\n&quot;);
		for (int j = 1; j &lt; 2500; ++j)
			printf(&quot;%d %d %d\n&quot;, rand() % j, j, 1 + rand() % 1000);
		printf(&quot;\n&quot;);
	}
	return 0;
}</code></pre><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><h2>参考</h2><ul><li
id="alp10" ><em>[ALP'10]</em> <a
href="http://hi.baidu.com/alpc32/blog/item/009edb7bdb12eee22f73b35a.html"  title="天津站B题 Building Roads"  target="_blank" >alpc32:《天津站B题 Building Roads》</a></li></ul><div
style="margin-top:15px;" ><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><strong>原创文章，转载请注明来源：</strong><a
href="http://euyuil.com/3114/acm-icpc-2010-tianjin-building-roads-solution/" >http://euyuil.com/3114/acm-icpc-2010-tianjin-building-roads-solution/</a></p></div> ]]></content:encoded> <wfw:commentRss>http://euyuil.com/3114/acm-icpc-2010-tianjin-building-roads-solution/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>ACM/ICPC 2009 合肥现场赛 Mersenne Prime 题解</title><link>http://euyuil.com/3110/acm-icpc-2009-hefei-mersenne-prime-solution/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=acm-icpc-2009-hefei-mersenne-prime-solution</link> <comments>http://euyuil.com/3110/acm-icpc-2009-hefei-mersenne-prime-solution/#comments</comments> <pubDate>Sun, 05 Feb 2012 06:10:21 +0000</pubDate> <dc:creator>EUYUIL</dc:creator> <category><![CDATA[无类可分]]></category> <category><![CDATA[ACM]]></category> <category><![CDATA[区域赛]]></category> <category><![CDATA[数论]]></category> <category><![CDATA[现场赛]]></category> <category><![CDATA[题解]]></category> <category><![CDATA[高精度]]></category> <guid
isPermaLink="false">http://euyuil.com/?p=3110</guid> <description><![CDATA[这道题认真做起来确实比较复杂，要求判断梅森素数。 梅森素数其实比较少，可以说少得还挺可怜的。数据范围是 1 到 257. 而且本题的最大数 2257 的位数也不多，而且其中没有多少素数。但是如果用打表，那就水了。 但是如果不打表，要用到高精度；不仅用到高精度，还要用到大素数的判断。这样的话传统的素数判定是不行的，要用到 Miller-Rabin 算法的高精版本。 最后我采取了一种……略无耻的做法，就是——用 Java! 这个问题上，Java 的好处就是封装了高精类，而且它居然也有 Miller-Rabin 算法。Java 的文档中说，如果迭代 k 次，那么那个算法正确的概率是 [latex]1 &#8211; (\frac{1}{2})^{k}[/latex]. 那么考虑到要判断 257 个数，我要让错误的概率在 [latex]\frac{1}{257}[/latex] 左右，我就果断迭代了 8 次。 代码如下： import java.util.*; import java.math.*; public final class Main { private static BigInteger one = BigInteger.ONE; private static BigInteger two = new BigInteger(&#34;2&#34;); private static [...]]]></description> <content:encoded><![CDATA[<p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这道题认真做起来确实比较复杂，要求判断<a
href="http://zh.wikipedia.org/zh/%E6%A2%85%E6%A3%AE%E7%B4%A0%E6%95%B0"  title="维基百科：梅森素数"  target="_blank" >梅森素数</a>。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">梅森素数其实比较少，可以说少得还挺可怜的。数据范围是 1 到 257. 而且本题的最大数 2<sup>257</sup> 的位数也不多，而且其中没有多少素数。但是如果用打表，那就水了。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">但是如果不打表，要用到高精度；不仅用到高精度，还要用到大素数的判断。这样的话传统的素数判定是不行的，要用到 <em>Miller-Rabin</em> 算法的高精版本。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">最后我采取了一种……略无耻的做法，就是——用 Java!</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><span
id="more-3110" ></span></p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">这个问题上，Java 的好处就是封装了高精类，而且它居然也有 <em>Miller-Rabin</em> 算法。Java 的文档中说，如果迭代 k 次，那么那个算法正确的概率是 [latex]1 &#8211; (\frac{1}{2})^{k}[/latex]. 那么考虑到要判断 257 个数，我要让错误的概率在 [latex]\frac{1}{257}[/latex] 左右，我就果断迭代了 8 次。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">代码如下：</p><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>import java.util.*;
import java.math.*;
public final class Main {
	private static BigInteger one = BigInteger.ONE;
	private static BigInteger two = new BigInteger(&quot;2&quot;);
	private static BigInteger[] M = new BigInteger[258];
	private static boolean[] isPrime = new boolean[258];
	public static void main(String[] args) {
		M[0] = one;
		for (int i = 1; i &lt; 258; ++i)
			M[i] = M[i - 1].multiply(two);
		for (int i = 0; i &lt; 258; ++i)
			M[i] = M[i].subtract(one);
		for (int i = 0; i &lt; 258; ++i)
			isPrime[i] = M[i].isProbablePrime(8);
		// for (int i = 0; i &lt; 258; ++i)
		// System.out.println(M[i] + &quot;:&quot; + (isPrime[i] ? &quot;Prime&quot; : &quot;NotPrime&quot;));
		Scanner cin = new Scanner(System.in);
		while (cin.hasNext()) {
			int n = cin.nextInt();
			if (n == 0) break;
			System.out.println(n + &quot;:&quot; + (isPrime[n] ? &quot;Prime&quot; : &quot;NotPrime&quot;));
		}
	}
}</code></pre><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><div
style="margin-top:15px;" ><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><strong>原创文章，转载请注明来源：</strong><a
href="http://euyuil.com/3110/acm-icpc-2009-hefei-mersenne-prime-solution/" >http://euyuil.com/3110/acm-icpc-2009-hefei-mersenne-prime-solution/</a></p></div> ]]></content:encoded> <wfw:commentRss>http://euyuil.com/3110/acm-icpc-2009-hefei-mersenne-prime-solution/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>ACM/ICPC2009 哈尔滨现场赛 YY and YY Again 题解</title><link>http://euyuil.com/3107/acm-icpc-2009-harbin-yy-and-yy-again-solution/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=acm-icpc-2009-harbin-yy-and-yy-again-solution</link> <comments>http://euyuil.com/3107/acm-icpc-2009-harbin-yy-and-yy-again-solution/#comments</comments> <pubDate>Sun, 05 Feb 2012 05:57:39 +0000</pubDate> <dc:creator>EUYUIL</dc:creator> <category><![CDATA[无类可分]]></category> <category><![CDATA[ACM]]></category> <category><![CDATA[区域赛]]></category> <category><![CDATA[字符串处理]]></category> <category><![CDATA[水题]]></category> <category><![CDATA[现场赛]]></category> <category><![CDATA[题解]]></category> <guid
isPermaLink="false">http://euyuil.com/?p=3107</guid> <description><![CDATA[水题。弄一个 256 元素的数组，先全初始化为 0, 然后把大写的 &#8216;A&#8217; 到 &#8216;Z&#8217; 为下标的地方分别初始化为 1 到 26 就可以了。然后每行每行地读进来，把字符作为下标，取刚才那个数组的相应数字，加在一个变量里，输出就好了。 代码如下： #include &#60;cstdio&#62; using namespace std; int score_table[256] = {0}; inline void init() { for (char ch = 'A'; ch &#60;= 'Z'; ++ch) score_table[ch] = ch - 'A' + 1; } char buffer[222]; int main() { init(); while (gets(buffer)) { int score [...]]]></description> <content:encoded><![CDATA[<p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">水题。弄一个 256 元素的数组，先全初始化为 0, 然后把大写的 &#8216;A&#8217; 到 &#8216;Z&#8217; 为下标的地方分别初始化为 1 到 26 就可以了。然后每行每行地读进来，把字符作为下标，取刚才那个数组的相应数字，加在一个变量里，输出就好了。</p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><span
id="more-3107" ></span></p><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;">代码如下：</p><pre class="crayon-plain-tag"   style="padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono'padding:.5em 1em;border:solid 1px #9f9f9f;background:#f1f1f1;margin-left:1em;font-family:'Yahei Mono''Yahei Consolas Hybrid''Yahei Consolas Hybrid'ConsolasConsolas'Courier New''Courier New'monospace;monospace;"><code>#include &lt;cstdio&gt;
using namespace std;
int score_table[256] = {0};
inline void init()
{
	for (char ch = 'A'; ch &lt;= 'Z'; ++ch)
		score_table[ch] = ch - 'A' + 1;
}
char buffer[222];
int main()
{
	init();
	while (gets(buffer))
	{
		int score = 0;
		for (char *p = buffer; *p; ++p)
			score += score_table[*p];
		if (score &gt; 100)
			printf(&quot;INVALID\n&quot;);
		else
			printf(&quot;%d\n&quot;, score);
	}
	return 0;
}</code></pre><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><div
style="margin-top:15px;" ><p
style="margin:0;padding:0;line-height:1.75em;text-indent:2em;margin:0;padding:0;line-height:1.75em;text-indent:2em;"><strong>原创文章，转载请注明来源：</strong><a
href="http://euyuil.com/3107/acm-icpc-2009-harbin-yy-and-yy-again-solution/" >http://euyuil.com/3107/acm-icpc-2009-harbin-yy-and-yy-again-solution/</a></p></div> ]]></content:encoded> <wfw:commentRss>http://euyuil.com/3107/acm-icpc-2009-harbin-yy-and-yy-again-solution/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> </channel> </rss>
