2022“杭电杯”中国大学生算法设计超级联赛(1)部分题题解

Ball

这个题如果我们就直接按照题意懂点的角度去思考问题的话,发现很难实现这个操作...
这个时候就要换个角度,可以尝试从边的角度去思考这个题。
如果从边的角度去思考问题的话,这个题就要求找到三个边,使得长度为中间的边的为质数。
既然要求由距离的限制,我们不妨将所有的边从小到大排序,排完序之后考虑从小到大枚举每一条边,这样当我们枚举到i时,比i小的边我们都已经枚举过了。到第i条边时,我们只需要找x连的比i小边,y连的比i大的边。正好我们可以在之前的枚举中求完答案后,我们可以做一个标记。这样就知道哪条边,哪条边大。我们考虑用bitset去存一个点所连的边的关系。为1说明,比当前i小。s[i][j]表示i-j这条边比当前边的权值小。则我们可以直接让s[x]^s[y]即可。两者之间1的个数即为答案。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2010,M=2e6+10,maxn=2e5+10;
int n,m,T,px[N],py[N];
bool vis[maxn+10];
struct wy{int x,y,v;}b[M];
bitset<N>s[N];
inline int dis(int x,int y)
{
	return abs(px[x]-px[y])+abs(py[x]-py[y]);
}
int main()
{
//	freopen("1.in","r",stdin); 
	for(int i=2;i<=maxn;++i)
		for(int j=2;i*j<=maxn;++j) vis[i*j]=1;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i)
		{
			scanf("%d%d",&px[i],&py[i]);
			s[i].reset();
		}
		int cnt=0;
		for(int i=1;i<=n;++i)
			for(int j=i+1;j<=n;++j) b[++cnt]={i,j,dis(i,j)};
		sort(b+1,b+cnt+1,[&](wy a,wy b){return a.v<b.v;});
		ll ans=0;
		for(int i=1;i<=cnt;++i)
		{
			if(!vis[b[i].v]) ans+=(s[b[i].x]^s[b[i].y]).count();
			s[b[i].x][b[i].y]=1;
			s[b[i].y][b[i].x]=1;
		}
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2022-07-21 11:15  逆天峰  阅读(44)  评论(0编辑  收藏  举报
作者:逆天峰
出处:https://www.cnblogs.com/gcfer//