Mishka and trip(CodeForces - 703B)
题目描述:
Little Mishka is a great traveller and she visited many countries. After thinking about where to travel this time, she chose XXX — beautiful, but little-known northern country.
Here are some interesting facts about XXX:
- XXX consists of n cities, k of whose (just imagine!) are capital cities.
- All of cities in the country are beautiful, but each is beautiful in its own way. Beauty value of i-th city equals to ci.
- All the cities are consecutively connected by the roads, including 1-st and n-th city, forming a cyclic route 1 — 2 — ... — n — 1. Formally, for every 1 ≤ i < n there is a road between i-th and i + 1-th city, and another one between 1-st and n-th city.
- Each capital city is connected with each other city directly by the roads. Formally, if city x is a capital city, then for every 1 ≤ i ≤ n, i ≠ x, there is a road between cities x and i.
There is at most one road between any two cities.
Price of passing a road directly depends on beauty values of cities it connects. Thus if there is a road between cities i and j, price of passing it equals ci·cj.
Mishka started to gather her things for a trip, but didn't still decide which route to follow and thus she asked you to help her determine summary price of passing each of the roads in XXX. Formally, for every pair of cities a and b (a < b), such that there is a road between a and b you are to find sum of products ca·cb. Will you help her?
翻译一下:
小MishKa是一个很棒的旅行家,她游览过许多国家。在仔细想了一下这次该去哪玩之后,她选择去XXX——一个美丽,但很小众的北部国家。
这是她选择这个国家的原因——一些有趣的事实:
- XXX拥有n座城市,其中有k座作为省会城市。
- 这个国家所有的城市都很美丽,但是每一个美丽的城市都有她的独特之处。她特地为每个城市设置了一个“美丽值”,第i座城市的“美丽值”为ci
- 每座城市都被许多条道路连接着,从第一座城市到第二座城市,再从第二座城市到第三座城市……再从第n座城市到第1座城市,组成了一个环行路(1-2-3……-n-1)。正式地,对于每一座城市(1 <= i <=n),在第i和第i+1座城市之间会有一条路,另外还有一条路在第n和第一条路之间。
- 每一座省会城市都与其他的所有城市有且仅有一条路连接,正式的,如果x城市是省会城市,那么对于除它之外的所有城市(1 <= i <= n,i ≠ x),都会有一条路在它们(i,x)之间。
通过一条路的过路费只取决于这条路所连接的两座城市的魅力值。因此如果在城市i和城市j之间有一条路,那么它的过路费为ci*cj。
Mishka已经开始整理行装,但她仍未决定如何选择路线,所以她想让你帮她算出XXX国家所有道路的过路费之和。。(既然有第四条下边那句话,后边那段文字不知道还有何存在的意义。。除了迷惑我。。。。)
输入
The first line of the input contains two integers n and k (3 ≤ n ≤ 100 000, 1 ≤ k ≤ n) — the number of cities in XXX and the number of capital cities among them.
The second line of the input contains n integers c1, c2, ..., cn (1 ≤ ci ≤ 10 000) — beauty values of the cities.
The third line of the input contains k distinct integers id1, id2, ..., idk (1 ≤ idi ≤ n) — indices of capital cities. Indices are given in ascending order.
翻译一下:
第一行是两个整数n(3 <= n <= 100000)和k(1 <= k <= n)——XXX国家的所有城市及省会城市的个数。
第二行是n个整数c1、c2、……、cn(1 <= ci <= 10000)——每座城市的美丽值。
第三行是k个确切的整数值id1、id2、……、idk(1 <= idi <= n)——每座省会城市在所有城市集合里的序号。
输出
Print the only integer — summary price of passing each of the roads in XXX.
翻译一下
只输出唯一的一个整数——XXX国家的所有道路的过路费之和
题目小贴士
This image describes first sample case:
It is easy to see that summary price is equal to 17.
This image describes second sample case:
![题目小贴士][1]
It is easy to see that summary price is equal to 71.
第一次尝试
一开始做的思路:先设置省会数组,用于区分普通城市和省会城市,再对所有城市进行遍历。遍历过程中,若当前城市为省会,则计算所有与其相连道路的过路费(不包括在它之前遍历到的省会与其之间的道路);若为普通城市,当前结点的下一个结点为头结点,则计算当前城市与头节点之间路径的过路费,加入到总路径中,否则计算当前结点与下一个节点道路的过路费,计算到总路径中。
在代码中用到了双重循环,时间复杂度为O(n2),由于题目限制运行时间是1000ms,粗略估计遍历城市的循环最坏情况下会执行10000*10000=100000000—,一亿次。果然提交后题目报错:Time limit。
#include<stdio.h>
#include<stdlib.h>
#define N 100000
int main()
{
int n, k;
int c[N];
int id[N];
int sum = 0;
int iflag;
int cap[N] = { 0 };
scanf("%d %d", &n, &k);
for (int i = 1; i < n + 1; i++) //初始化城市
{
scanf("%d", &c[i]);
}
for (int i = 1; i < k + 1; i++)
{
scanf("%d", &id[i]);
cap[id[i]] = 1;
} //读取省会城市个数
for (int i = 1; i < n + 1; i++)
{
if (cap[i] == 1)
{
for (int j = 1; j < n + 1; j++)
{
if (j < i&&cap[j] == 1 || i == j)
{
continue;
}
else
{
sum += (c[i] * c[j]);
}
}
continue;
}
if ((i + 1) % (n + 1) == 0) //若下一个结点循环至头结点
{
if (cap[(i + 2) % (n + 1)] != 1) //若不为省会
{
sum += c[i] * c[1];
continue;
}
}
else if (cap[(i + 1) % (n + 1)] != 1) //否则 若不为省会
{
sum += c[i] * c[(i + 1) % (n + 1)];
continue;
}
}
printf("%d", sum);
return 0;
}
第二次尝试
第二次尝试消去二重循环,改变一种思路。设置了一些辅助变量。
可以先计算全部城市的美丽值之和作为help_sum,省会城市的美丽值之和作为help_sum2,再分别讨论遍历省会城市和普通城市的情况,若为省会城市,则只需计算其与所有城市的过路费之和,再减去与省会城市多算的过路费即为该省会城市所有未走过道路需交过路费;若为普通城市,则判断下个城市再决定是否交过路费。
再次提交显示wrong answer on test 10,原因为设置变量长度太小。int的范围为[-2^31, 2^31-1]即 [-2147483648,2147483647],21亿;long long 的范围为 [-2^63, 2^63-1]即 [-9223372036854775807, 9223372036854775807],100亿亿,更改大数据变量为long long后提交,代码顺利通过。 ^ ^
代码如下:
#include<stdio.h>
#include<stdlib.h>
#define N 100004
int main()
{
int n, k;
int c[N];
int *id;
long long sum = 0;
int *cap;
long long help_sum = 0;
long long help_sum2 = 0;
scanf("%d %d", &n, &k);
if (n<3 || k>n || k < 1)
return 1;
cap = (int *)malloc((n + 1) * sizeof(int));
id = (int *)malloc((k + 1) * sizeof(int));
for (int i = 1; i < n + 1; i++)
{
scanf("%d", &c[i]);
help_sum += c[i];
cap[i] = 0;
}
for (int i = 1; i < k + 1; i++)
{
scanf("%d", &id[i]);
cap[id[i]] = 1;
help_sum2 += c[id[i]];
}
for (int i = 1; i < k + 1; i++)
{
sum += ((help_sum - c[id[i]])*c[id[i]]);
sum -= ((help_sum2 - c[id[i]])*c[id[i]]);
help_sum2 -= c[id[i]];
}
for (int i = 1; i < n; i++)
{
if (cap[i] != 1 && cap[i + 1] != 1)
{
sum += c[i] * c[i + 1];
}
}
if (cap[n] != 1 && cap[1] != 1)
{
sum += c[1] * c[n];
}
printf("%lld\n", sum);
return 0;
}
小小总结
这也是一道很简单的题目,并没有涉及复杂的数据结构知识。
感觉该题不过是解法非常难想,各方面限制较多。花了将近半天的时间(12个小时。。)做这么一道题目,从最开始不断地优化时间复杂度,再到一个测试用例无法通过不断检查代码,最终通过使用long long 扩大了变量范围才最终ac。真的是一次对意志力的小考验,差点就没能坚持到ac。所以以后写题目更要注意优化代码,尽量不要使用多重循环,数据如果过大则要使用范围更大的数据类型,更重要的是在以后的刷题路上一定要保持对自己的信心!
[1]: https://odzkskevi.qnssl.com/978f7393c18621d84fea150293a264cc?v=1485951373
网友评论