Jogging-2020杭电多校7

题意

给出一个点 ((x,y)) ,满足 (gcd(x,y)>1)。每次可以从当前的点到达其周围 (8) 个点中满足坐标 (gcd(x',y')>1) 的点中的一个,定义 (P_t) 为返回出发点的概率,求 (lim limits_{t ightarrowinfty}P_t)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6853

分析

当起点和对角线联通,概率为 (0)。可以走的联通块的大小并不会很大,可以直接 (bfs) 搜索,判断是否联通。否则答案为 "起点度数+1" 除以 "总度数+n"。

关于这两个结论,自己并不会证明,希望大佬指点。

代码

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<ll,ll>pll;

int dx[8]={-1,-1,-1,0,1,1,1,0};
int dy[8]={-1,0,1,1,1,0,-1,-1};
queue<pll>que;
map<int,map<ll,ll> >mp;
vector<pll>point;
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
bool check(ll x,ll y)
{
    if(gcd(x,y)>1&&mp[x][y]==0) return 1;
    return 0;
}
bool bfs(ll sx,ll sy)//联通块不大
{
    mp.clear();
    point.clear();
    while(!que.empty())
        que.pop();
    mp[sx][sy]=1;
    que.push(make_pair(sx,sy));
    while(!que.empty())
    {
        pll now=que.front();
        que.pop();
        if(now.first==now.second) return 1;
        point.pb(now);
        for(int i=0;i<8;i++)
        {
            ll tx=now.first+dx[i];
            ll ty=now.second+dy[i];
            if(check(tx,ty))
            {
                if(tx==ty) return 1;
                que.push(make_pair(tx,ty));
                mp[tx][ty]=1;
            }
        }
    }
    return 0;
}
int cont(ll x,ll y)
{
    int cot=0;
    for(int i=-1;i<=1;i++)
    {
        for(int j=-1;j<=1;j++)
        {
            if(gcd(x+i,y+j)>1)
                cot++;
        }
    }
    return cot;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll x,y;
        int tol=0,cnt=0;
        scanf("%lld%lld",&x,&y);
        if(bfs(x,y))
        {
            printf("0/1
");
            continue;
        }
        for(int i=0;i<point.size();i++)
            tol+=cont(point[i].first,point[i].second);//总度数+n
        cnt=cont(x,y);//起点度数+1
        ll g=gcd(tol,cnt);
        printf("%lld/%lld
",cnt/g,tol/g);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/1024-xzx/p/13489663.html