1. 程式人生 > >BZOJ[2563] 阿貍和桃子的遊戲

BZOJ[2563] 阿貍和桃子的遊戲

open display urn pre gif out 每一個 %d 排序

這個題的正解和之前做過的網絡流的文理分科差不多,都是一個把對兩個點都有貢獻的邊的貢獻分別加給兩個點;

在這個題裏,首先考慮阿貍拿走了所有的邊權與點權,那麽現在桃子的分數為0,阿貍的分數為所有權值的加和,那麽考慮桃子選每一個點所造成的貢獻,每當桃子選了一個點v,則桃子的分數加上w[v],阿貍的分數減去w[v],於此同時,阿貍失去了所有以v為一個端點的邊的權值,所以選v時,桃子將差距縮小了2*w[v]+∑以v為一個端點的邊的權值,由於每次只加了一次邊權,所以當選了一個邊的兩端點時,貢獻就算了2次,剛好符合遊戲規則(兩次是同點一樣,桃子+w,阿貍-w,所以是2*w);

先求出阿貍的sum,然後每一個點的權值就是2*w[v]+∑以v為一個端點的邊的權值,然後sort排序,從大到小選N/2個,要註意因為是輪流選,所以桃子只能隔著選,

Code

技術分享
 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <iostream>
 6 #include <algorithm>
 7 # define maxn 10010
 8 # define max_m 100010
 9 using namespace std;
10 typedef long long LL;
11 int n,m;
12 LL val[maxn];
13 struct
node{ 14 int u,v,nxt; LL w; 15 }g[2*max_m]; 16 int adj[maxn],e; 17 void add(int u,int v,LL w){ 18 g[e].u=u; g[e].v=v; g[e].w=w; g[e].nxt=adj[u]; 19 adj[u]=e++; 20 } 21 LL sum; 22 void init(){ 23 scanf("%d%d",&n,&m); 24 for(int i=1;i<=n;i++) scanf("%lld",&val[i]),sum+=val[i];
25 memset(adj,-1,sizeof(adj)); 26 int x,y; LL z; 27 for(int i=1;i<=m;i++){ 28 scanf("%d%d%lld",&x,&y,&z); 29 add(x,y,z); add(y,x,z); 30 sum+=z; 31 } 32 sum=-sum; 33 } 34 bool cmp(const int a,const int b){return a>b;} 35 void work(){ 36 for(int i=1;i<=n;i++){ 37 val[i]*=2; 38 for(int j=adj[i];j!=-1;j=g[j].nxt){ 39 int v=g[j].v; 40 val[i]+=g[j].w; 41 } 42 } 43 sort(val+1,val+n+1,cmp); 44 for(int i=1;i<=n;i+=2){ 45 sum+=val[i]; 46 } 47 cout<<sum<<endl; 48 } 49 int main(){ 50 // freopen("a.in","r",stdin); 51 init(); 52 work(); 53 }
View Code

BZOJ[2563] 阿貍和桃子的遊戲