原題鏈接:
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;
}