2019/9/2 校内练习赛 考试报告

A.一道图论神题(god.cpp)

题目链接

题意

给定一张无向图,每个点有正点权,删掉一个点的代价为与它相连的所有未被删除的节点的权值和,求删掉所有点的最小代价.

解法

考虑任意两个相连的点\(u\)\(v\).

\(u\)点权值为\(a\).

\(v\)点权值为\(b\).

\(u\)相连的节点的权值和,减去\(v\)点权值,结果为\(c\).

\(v\)相连的节点的权值和,减去\(u\)点权值,结果为\(d\).

那么,如果先删除\(u\),再删除\(v\),代价为\(c+b+d\).

如果先删除\(v\),再删除\(u\),代价为\(d+a+c\).

那么如果\(a>b\),应该先删除\(u\),再删除\(v\).

否则,应该先删除\(v\),再删除\(u\).

即应该先删除\(u,v\)中权值大的点.

显然该结论可以推广到所有点.

所以贪心策略为由大到小删除权值大的点.

代码

#include<bits/stdc++.h>
const int SIZE=200005;
int x[SIZE],head[SIZE],nex[SIZE],to[SIZE],Tot,Ans[SIZE];
void Link(int u,int v)
{
	nex[++Tot]=head[u];head[u]=Tot;to[Tot]=v;
	nex[++Tot]=head[v];head[v]=Tot;to[Tot]=u;
}

struct node
{
	int x,pos;
	bool operator <(const node &p)const
	{
		return x>p.x;
	}
}Tem[SIZE];

bool Removed[SIZE];
long long Tot_Ans;
int main()
{
	freopen("god.in","r",stdin);
	freopen("god.out","w",stdout);
	int n,m,u,v;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&x[i]);
		Tem[i]=(node){x[i],i};
	}
	std::sort(Tem+1,Tem+1+n);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&u,&v);
		Link(u,v);
		Ans[u]+=x[v];
		Ans[v]+=x[u];
	}
	for(int o=1;o<=n;o++)
	{
		u=Tem[o].pos;
		for(int i=head[u];i;i=nex[i])
		{
			v=to[i];
			if(Removed[v])continue;
			Ans[v]-=x[u];
		}
		Tot_Ans+=Ans[u];
		Removed[u]=1;
	}
	printf("%lld",Tot_Ans);
	return 0;
}

B.位运算(bit.cpp)

题目链接

题意

定义数字\(n\)的价值\(k\)\(|n|\)各位数字之和.

求满足小于\(n\),价值为\(k+1\),且最大的数.

\(|n| \le 10^{100000}\).

解法

分类讨论.

\(n\)为负数,从低位向高位找第一个一个不为\(9\)的位置,给这个位置\(+1\)即可.如果所有位上都是\(9\),在最前面补\(1\).

\(n\)为非负数,考虑寻找这样一个位置:

  • 这个位置可以\(-1\)(即这个位置上的数不为\(0\)).
  • 这个位置往右的那些位置的数字和,可以\(+2\).

只要可以找到这样的位置,就可以找到一个满足题意的正数...

等待更新

posted @ 2019-09-03 18:17  TaylorSwift13  阅读(125)  评论(0编辑  收藏  举报