解题笔记-CodeForces-884C Bertown Subway
0 题面
C. Bertown Subway
The construction of subway in Bertown is almost finished! The President of Berland will visit this city soon to look at the new subway himself.
There are n stations in the subway. It was built according to the Bertown Transport Law:
- For each station i there exists exactly one train that goes from this station. Its destination station is pi, possibly pi = i;
- For each station i there exists exactly one station j such that pj = i.
The President will consider the convenience of subway after visiting it. The convenience is the number of ordered pairs (x, y) such that person can start at station x and, after taking some subway trains (possibly zero), arrive at station y (1 ≤ x, y ≤ n).
The mayor of Bertown thinks that if the subway is not convenient enough, then the President might consider installing a new mayor (and, of course, the current mayor doesn't want it to happen). Before President visits the city mayor has enough time to rebuild some paths of subway, thus changing the values of pi for not more than two subway stations. Of course, breaking the Bertown Transport Law is really bad, so the subway must be built according to the Law even after changes.
The mayor wants to do these changes in such a way that the convenience of the subway is maximized. Help him to calculate the maximum possible convenience he can get!
Input
The first line contains one integer number n (1 ≤ n ≤ 100000) — the number of stations.
The second line contains n integer numbers p1, p2, ..., pn (1 ≤ pi ≤ n) — the current structure of the subway. All these numbers are distinct.
Output
Print one number — the maximum possible value of convenience.
Examples
input
3
2 1 3
output
9
input
5
1 5 4 3 2
output
17
Note
In the first example the mayor can change p2 to 3 and p3 to 1, so there will be 9 pairs: (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3).
In the second example the mayor can change p2 to 4 and p3 to 5.
中文大意:
有 n 个车站(车站编号为1~n),满足 Bertown Transport Law:
- 对于每个车站 i ,一定有目的地车站 pi(允许 pi = i )
- 对于每个车站 i ,存在唯一的 pj = i
舒适度是有序数对 (x, y) 的数量,使得从车站 x 出发能够到达车站 y(允许 x = y)。
总统即将来访,市长想要提升舒适度,便试图改造线路。
他能够改变某些车站的 pi 值,但他最多调整两个,且调整后的车站仍满足 Bertown Transport Law,求最大舒适度。
1 思路
本题中描述的车站,以及车站间的关系,能够使用有向图描述。
根据题面中描述的"Bertown Transport Law",可以断定每个车站必然是两个状态之一:
- 车站形成自环。
- 车站与其它若干个车站形成环。
而形成环的两个部分,必然可以通过改变两个车站的指向,使两个部分形成新的环。
一个环中,任意两点必然连通,算上其自身,则 n 个车站形成的环中 (x, y) 的数量应为 n2,即 n 个车站形成的环的舒适度为 n2.
考虑使用 DFS 遍历出每个环的车站数量,并将最大的两个结合,此时的舒适度就是最大的舒适度。
PS: 若有两个环,分别有 a, b 个车站,则两个环结合后的新环比原先的舒适度增加 2ab,推导如下。
设原先两个环的总舒适度为 R1,两个环结合后的新环的舒适度为R2,则有:

那么
2 代码
2.1 错误示例
比赛进行的时候,代码无论如何也无法AC,在此贴出三份错误示例。
错误示例 1 (Runtime Error)
#include <iostream>
#include <vector>
#include <algorithm>
#define MAXN 100000+5
using std::vector;
using std::sort;
int p[MAXN];
bool visited[MAXN];
int main()
{
int n, t = 0;
long long r = 0;
vector<long long> count;
std::cin >> n;
for(int i = 1; i <= n; i++)
{
std::cin >> p[i];
}
for(int i = 1; i <= n; i++)
{
if(visited[i] == true)
continue;
int cnt = 1;
int x = p[i];
visited[x] = true;
while(x != i)
{
x = p[x];
visited[x] = true;
cnt++;
}
count.push_back(cnt);
t++;
}
sort(count.begin(), count.end());
r = count[t - 1] + count[t - 2];
r = r * r;
for(int i = 0; i < count.size() - 2; i++)
{
r += count[i];
}
std::cout << r;
return 0;
}
错因:未考虑只有一个环的情况,导致下标越界。
解决:加上判断;或不使用 vector,直接使用两个变量记录,见下例。
错误示例 2 (部分测试点答案错误)
#include <iostream>
#define MAXN 100000+5
int p[MAXN];
bool visited[MAXN] = {false};
int main()
{
std::ios::sync_with_stdio(false);
int max1 = 0, max2 = 0;
int n, t = 0;
long long r = 0;
std::cin >> n;
for(int i = 1; i <= n; i++)
{
std::cin >> p[i];
}
for(int i = 1; i <= n; i++)
{
if(visited[i] == true)
continue;
int cnt = 1;
int x = p[i];
visited[x] = true;
while(x != i)
{
x = p[x];
visited[x] = true;
cnt++;
}
r += cnt * cnt;
if(cnt > max1)
{
max1 = cnt;
}
else if(cnt > max2)
{
max2 = cnt;
}
}
r -= max1 * max1 + max2 * max2;
r += (max1 + max2) * (max1 + max2);
std::cout << r;
return 0;
}
错因:最后对 r 操作时,由于类型不一,数据丢失;以及 max1, max2 的问题,见下例。
解决:强制转换;或直接将 max1, max2 定义为 long long 类型。
错误示例 3 (部分测试点答案错误)
#include <iostream>
#define MAXN 100000+5
int p[MAXN];
bool visited[MAXN] = {false};
int main()
{
std::ios::sync_with_stdio(false);
int n, t = 0;
long long r = 0;
long long max1 = 0, max2 = 0;
std::cin >> n;
for(int i = 1; i <= n; i++)
{
std::cin >> p[i];
}
for(int i = 1; i <= n; i++)
{
if(visited[i] == true)
continue;
long long cnt = 1;
int x = p[i];
visited[x] = true;
while(x != i)
{
x = p[x];
visited[x] = true;
cnt++;
}
r = r + cnt * cnt;
if(cnt > max1)
{
max1 = cnt;
}
else if(cnt > max2)
{
max2 = cnt;
}
}
r = r + 2LL * max1 * max2;
std::cout << r;
return 0;
}
错因:在更新 max1 的值前,未将 max1 赋予 max2,导致部分情况下 max2 不正确。
解决:在 max1 = cnt; 前增加 max2 = max1;
2.2 正确示例
在剖析完错误后,以下是两份正确示例。
正确示例 1 (利用 vector)
#include <iostream>
#include <vector>
#include <algorithm>
#define MAXN 100000+5
using std::sort;
int p[MAXN];
bool visited[MAXN] = {false};
int main()
{
std::ios::sync_with_stdio(false);
std::vector<long long> v;
int n, t = 0;
long long r = 0;
long long max1 = 0, max2 = 0;
std::cin >> n;
for(int i = 1; i <= n; i++)
{
std::cin >> p[i];
}
for(int i = 1; i <= n; i++)
{
if(visited[i] == true)
continue;
long long cnt = 1;
int x = p[i];
visited[x] = true;
while(x != i)
{
x = p[x];
visited[x] = true;
cnt++;
}
v.push_back(cnt);
}
sort(v.begin(), v.end());
if(v.size() >= 2)
{
r = v[v.size() - 2] + v[v.size() - 1];
r = r * r;
for(int i = 0; i < v.size() - 2; i++)
{
r += v[i] * v[i];
}
}
else
{
r = v[0] * v[0];
}
std::cout << r;
return 0;
}
正确示例 2 (利用 max1, max2 变量)
#include <iostream>
#define MAXN 100000+5
int p[MAXN];
bool visited[MAXN] = {false};
int main()
{
std::ios::sync_with_stdio(false);
int n, t = 0;
long long r = 0;
long long max1 = 0, max2 = 0;
std::cin >> n;
for(int i = 1; i <= n; i++)
{
std::cin >> p[i];
}
for(int i = 1; i <= n; i++)
{
if(visited[i] == true)
continue;
long long cnt = 1;
int x = p[i];
visited[x] = true;
while(x != i)
{
x = p[x];
visited[x] = true;
cnt++;
}
r = r + cnt * cnt;
if(cnt > max1)
{
max2 = max1;
max1 = cnt;
}
else if(cnt > max2)
{
max2 = cnt;
}
}
r = r + 2LL * max1 * max2;
std::cout << r;
return 0;
}

浙公网安备 33010602011771号