• 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;
    }
    
  • 相关阅读:
    Linux基礎命令
    Linux_文件系統結構
    Linux_目錄結構與操作_基本命令
    JS简单打字小游戏demo
    开发板通过路由器访问外网
    VIM基本操作命令表
    破解source insight4.0
    进程控制
    静态库与动态库的制作和使用
    STM32建工程模板
  • 原文地址:https://www.cnblogs.com/gcfer/p/16501305.html
Copyright © 2020-2023  润新知