BZOJ 2563 阿狸和桃子的游戏
BZOJ 2563 阿狸和桃子的游戏
题意
给出一个图,每个点有点权\(v_i\),每条边有边权\(c_i\),两个人轮流选点,选择一个点可以获得这个点的点权,一条边的两个点如果都被一个人选了,那么这个人会获得这条边的边权。两者都采取最优的方案,问后手的分数减先手的分数是多少。
题解
看了题解之后感觉这道题目好妙啊。我们先分析对于一个人对一个点的选择对答案造成的影响:
1.如果一个点被这个人选择了,那么它的贡献是\(v_i\),如果这个点没有被选择,那么他的贡献是\(-v_i\)。
2.如果一条边的两个端点都被这个人选择了,那么它的贡献是\(c_i\),如果分别被两个人选择了,那么它的贡献是\(0\),如果都被另一个人选择了,那么它的贡献是\(-c_i\)。
而题目要我们求的两者的分数差,于是我们可以将\(ans\)减去所有的贡献,先默认由先手选择了,于是后手的选择对答案的影响会变成这样:
1.如果一个点被这个人选择了,那么它的贡献是\(2v_i\),否则贡献是\(0\)。
2.如果一条边的两个端点都被这个人选择了,那么它的贡献是\(2c_i\),如果分别被两个人选择了,那么它的贡献是\(c_i\),如果都被另一个人选择了,那么它的贡献是\(0\)。
这样做了改变之后,我们就可以把一个点的点权改为\(2v_i+\sum_{e=(i,v)} c(e)\),那么选择了这个点之后,获得的贡献仍然还是和之前一样的,并且不用考虑边权。然后我们就可以贪心的选择点,最后统计一下答案即可。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
#define PAUSE printf("Press Enter key to continue..."); fgetc(stdin);
const int N=1e5+500;
int n,m;
int val[N];
int ans=0;
/*==================Define Area================*/
int main() {
read(n);read(m);
for(int i=1;i<=n;i++) read(val[i]),ans-=val[i],val[i]*=2;
for(int i=1,u,v,c;i<=m;i++) read(u),read(v),read(c),ans-=c,val[u]+=c,val[v]+=c;
sort(val+1,val+1+n);
for(int i=2;i<=n;i+=2) ans+=val[i];
printf("%d\n",ans);
return 0;
}
「我不敢下苦功琢磨自己,怕终于知道自己并非珠玉;然而心中既存着一丝希冀,便又不肯甘心与瓦砾为伍。」