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).

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

等待更新

原文地址:https://www.cnblogs.com/TaylorSwift13/p/11454673.html