luogu P4643 [国家集训队]阿狸和桃子的游戏
题面传送门
首先,我们看到一个庞大的式子,好怕怕!
经\(rsjdalao\)解读,这就是所选的点权加上两个点都是自己的点围成的边的边权。
那么不就好做了,贪心!能拿点权大的点就拿大的点!
代码实现:
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int n,m,a[100039],x[100039],y[100039],z[100039],s[100039],ans,tot,so[100039];
inline bool cmp(int x,int y){
return a[x]>a[y];
}
int main(){
register int i;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) scanf("%d",&a[i]),so[i]=i;
for(i=1;i<=m;i++) scanf("%d%d%d",&x[i],&y[i],&z[i]);
sort(so+1,so+n+1,cmp);
for(i=1;i<=n;i++){
s[so[i]]=i&1;
if(i&1) ans+=a[so[i]];
else tot+=a[so[i]];
}
for(i=1;i<=m;i++){
if(s[x[i]]==s[y[i]]&&s[y[i]]==1) ans+=z[i];
if(s[x[i]]==s[y[i]]&&s[y[i]]==2) tot+=z[i];
}
printf("%d",ans-tot);
}
很悲惨地爆\(zero\)了。为什么?因为他还有边权,这样的贪心不能保证边权最大。
那么,爆搜!能骗几分是几分。
代码实现:
#include<cstdio>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,a[100039],x[100039],y[100039],z[100039],s[100039],ans=2147483647,tot,pus,now;
inline void dfs(int h,int now){
if(h>n) return;
if(now==n/2) {
tot=pus=0;
for(register int i=1;i<=n;i++){
if(s[i]) tot+=a[i];
else pus+=a[i];
}
for(register int i=1;i<=m;i++){
if(s[x[i]]==s[y[i]]&&s[y[i]]==1) tot+=a[i];
if(s[x[i]]==s[y[i]]&&s[y[i]]==2) pus+=a[i];
}
ans=min(ans,tot-pus);
return;
}
s[h]=1;
dfs(h+1,now+1);
s[h]=0;
dfs(h+1,now);
}
int main(){
register int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) scanf("%d",&a[i]);
for(i=1;i<=m;i++) scanf("%d%d%d",&x[i],&y[i],&z[i]);
dfs(1,0);
printf("%d",ans);
}
万紫千红吧,一分都没拿到,也不知道是\(dfs\)打挂了还是本来就不能用\(dfs\)。
重新关注一下题面: 为桃子的得分减去阿狸的得分。
题目为什么要这样出?不排除闲的无聊的可能性,但这可是国家集训队的题目!
想象一下,对于两个点,分类讨论一下。
设这两个点为\(x1\),\(x2\),点权为\(y1\),\(y2\),边权为\(z\)。
若都是一个人拿去了,那么得分为\(y1+y2+z\)。
若是不同人拿去了,那么分别得\(y1\)与\(y2\)分。
把不同人拿去的情况转换成不等式,得\(y1<y2\).
根据不等式的性质,两边同时加上\(\frac{z}{2}\),得\(y1+\frac{z}{2}<y2+\frac{z}{2}\)
将同一人拿去的情况转变一下,得\((y1+\frac{z}{2})+(y2+\frac{z}{2})\)
两式都不改变得分差值情况,所以我们可以把两个点围成一条边的边权平均分配到两个点上。
记得开\(double\)。
代码实现:
#include<cstdio>
#include<algorithm>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,x,y,z;
double a[100039],ans,tot;
inline void read(int &x){
char s=getchar();int f=1;x=0;
while(s<'0'||s>'9'){if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
x*=f;
}
int main(){
register int i,j;
read(n);read(m);
for(i=1;i<=n;i++) scanf("%lf",&a[i]);
for(i=1;i<=m;i++) read(x),read(y),read(z),a[x]+=z/2.0,a[y]+=z/2.0;
sort(a+1,a+n+1);
for(i=1;i<=n;i++) {
if(i&1) ans+=a[i];
else tot+=a[i];
}
printf("%.0lf",tot-ans);
}
思维题呀!思维题。