原题链接:
http://codeforces.com/problemset/problem/703/B
题意:
有n个城市,1-n形成一个环,其中有k个省会,每个省会应该和每个城市都连起来。每个城市有一个美丽值,两城市之间的连路的美丽值为两城市美丽值的乘积,要求所有连路的美丽值的总和。
分析:
首先想到的是先把所有情况加起来,再减去会重复的。但是写起来比较麻烦而且重复的难以理清,而且感觉怎么写都会超时。所以我们可以先不考虑省会的城市,连把环路的美丽值加起来,得ans=∑(n < i<=0)beauty[i]*beauty[(i+1)%n],并且记录所有城市美丽值的和sum(因为后面考虑首都的时候都是要乘其他的城市的美丽值然后求和)。在考虑首都的时候,只需要减去在sum中减去自己,并且把自己标记,用tmp暂存对于当前首都的sum值,标记是为了证明当前省会已经和其他所有城市连接过了,并且在sum值中已经减过,然后在处理后面的省会的时候,当相邻的没被标记【说明不是省会】,就需要把tmp减掉相邻的美丽值,因为在环路中已经计算过,接下来就是ans+=tmp×beauty[cap[i]]。跑完循环就是答案。复杂度O(n)
代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<cctype>
#include<list>
#define ll long long
#define ull unsigned long long
using namespace std;
const int maxn=100010;
const int inf=1<<30;
ll be[maxn];
ll ci[maxn];
bool flag[maxn];
int main()
{
//#define DEBUG
#ifdef DEBUG
freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif
int n,k;
scanf("%d%d",&n,&k);
ll sum=0;
ll ans=0;
for(int i=0;i<n;i++){
scanf("%I64d",&be[i]);
sum+=be[i];
}
for(int i=0;i<n;i++){
ans+=be[i]*be[(i+1)%n];
}
for(int i=0;i<k;i++){
scanf("%I64d",&ci[i]);
}
ll tmp;
for(int i=0;i<k;i++){
if(!flag[ci[i]-1]){
sum-=be[ci[i]-1];
flag[ci[i]-1]=1;
}
tmp=sum;
if(!flag[(ci[i]-2+n)%n]){
tmp-=be[(ci[i]-2+n)%n];
}
if(!flag[(ci[i])%n]){
tmp-=be[(ci[i])%n];
}
ans+=tmp*be[ci[i]-1];
}
printf("%I64d\n",ans);
return 0;
}
本文介绍了一个关于城市间道路美丽值总和的问题解决方案。通过优化算法,采用标记已处理的省会城市的方法,在O(n)的时间复杂度内计算出了所有连路的美丽值总和。
447

被折叠的 条评论
为什么被折叠?



