洛谷P4643 [國家集訓隊]阿狸和桃子的遊戲 & 初賽心情
洛谷P4643 [國家集訓隊]阿狸和桃子的遊戲
引入
其實是道小水題,沒有那麼多的資料結構和卡常。但是我就是喜歡這種題!giao!
(希望這道題不要變色啊……這可是我a的第一道黑題啊啊啊……
蒟蒻的心情激動不已啊
題目描述
阿狸和桃子正在玩一個遊戲,遊戲是在一個帶權圖G=(V, E)上進行的,設節點權值為w(v),邊權為c(e)。遊戲規則是這樣的:
-
阿狸和桃子輪流將圖中的頂點染色,阿狸會將頂點染成紅色,桃子會將頂點染成粉色。已經被染過色的點不能再染了,而且每一輪都必須給一個且僅一個頂點染色。
-
為了保證公平性,節點的個數N為偶數。
-
經過N/2輪遊戲之後,兩人都得到了一個頂點集合。對於頂點集合S,得分計算方式為
\sum_{v \in S}w(v) + \sum_{e=(u,v)\in E \land u,v\in S}c(e)v∈S∑w(v)+e=(u,v)∈E∧u,v∈S∑c(e)
由於阿狸石頭剪子布輸給了桃子,所以桃子先染色。兩人都想要使自己的分數比對方多,且多得越多越好。如果兩人都是採用最優策略的,求最終桃子的分數減去阿狸的分數。
輸入格式
輸入第一行包含兩個正整數N和M,分別表示圖G的節點數和邊數,保證N一定是偶數。
接下來N+M行。
前N行,每行一個整數w,其中第k行為節點k的權值。
後M行,每行三個用空格隔開的整數a b c,表示一條連線節點a和節點b的邊,權值為c。
輸出格式
輸出僅包含一個整數,為桃子的得分減去阿狸的得分。
輸入輸出樣例
輸入 #14 4 6 4 -1 -2 1 2 1 2 3 6 3 4 3 1 4 5輸出 #1
3
說明/提示
資料規模和約定
對於40%的資料,1 ≤ N ≤ 16。
對於100%的資料,1 ≤ N ≤ 10000,1 ≤ M ≤ 100000,-10000 ≤ w , c ≤ 10000。
Solution
先理解那個式子——
兩個人依次選點
而最終的得分等於
選的點數的和
再加上其選的每兩點之間的直接的邊之和
即:一條邊僅當它所連線的兩個點都被同一個人所選,這條邊的w才歸這個人所有。
邊和點都對答案有所影響,怎麼辦呢?要是隻有點權就好了啊!
欸……那能不能把邊權轉化為點權呢?可以的!把邊權對半分給邊就好了!
我們從一張圖中扣下來一條邊,仔細分析一下:
如圖,A和B是點(權),C是邊(權)。
如果直接使用上面的性質我們可以分類討論一下:
下面分4中情況
- 桃子把A和B都染成了粉色,那麼桃子得到了這ABC的權ans=(A+C/2)+(B+C/2)=A+B+C;
- 桃子把A染成了粉色,阿狸把B染成了紅色,那麼得分為(A+C/2)-(B+C/2)=A-B;
- 桃子把B染成了粉色,阿狸把B染成了紅色,那麼得分為(B+C/2)-(A+C/2)=B-A;
- 阿狸把A和B都染成了紅色,那麼得分為-(A+C/2)-(B+C/2)=-(A+B+C);
發現這和暴力加是一樣的!
所以,只要把邊權平分到兩個點上再進行排序,奇數偶數分配即可!
Code
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<map> 7 #include<set> 8 #include<queue> 9 #include<vector> 10 #define IL inline 11 #define re register 12 #define LL long long 13 #define ULL unsigned long long 14 #define re register 15 using namespace std; 16 17 template<class T>inline void read(T&x) 18 19 { 20 char ch=getchar(); 21 while(!isdigit(ch))ch=getchar(); 22 x=ch-'0';ch=getchar(); 23 while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} 24 } 25 inline int read() 26 { 27 int x=0; 28 char ch=getchar(); 29 while(!isdigit(ch))ch=getchar(); 30 x=ch-'0';ch=getchar(); 31 while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} 32 return x; 33 } 34 int G[55]; 35 template<class T>inline void write(T x) 36 { 37 int g=0; 38 do{G[++g]=x%10;x/=10;}while(x); 39 for(re int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n'); 40 } 41 int n,m; 42 double ans,a[10010]; 43 bool cmp(const double & a,const double & b){ 44 return a>b; 45 } 46 int main() 47 { 48 cin>>n>>m; 49 for(int i=1;i<=n;i++) cin>>a[i]; 50 for(int i=1,x,y;i<=m;i++) 51 { 52 double z; 53 cin>>x>>y>>z; 54 a[x]+=z/2; 55 a[y]+=z/2; 56 } 57 sort(a+1,a+n+1,cmp); 58 for(int i=1;i<=n;i++) if(i&1) ans+=a[i];else ans-=a[i]; 59 cout<<ans; 60 return 0; 61 }
小結
心情不錯,今天上午考完了初賽,估分77.5……希望能進複賽,當然,要是AFO的話……那就AFO吧……就當作是場錯付吧……
(要是不會真的 “考完初賽回來A了一道黑題,結果發現今年AFO了”吧?)呸呸呸,烏鴉嘴