F题直接DP做法

考虑倒着递推,从 递推到

假设当前数字为 now 此时的状态转移方程是:dp[i][j]=std::min(dp[i][j+1],dp[i+1][j])+1

再考虑使用传送门,我们另外开一个数组 vector<int>minDis(n+1)记录使用当前质因数传送门到达终点的最短距离,此时的状态转移方程为:dp[i][j]=std::min(dp[i][j],minDis[k]+1),其中 k 遍历 now 的所有质因数

最后由于所有 now 的质因数都可以通过 dp[i][j] 的步数到达终点,我们再将此时的 dp[i][j] 提供给 minDis,即:minDis[k]=std::min(minDis[k],dp[i][j]),其中 k 遍历所有 now 的质因数

最后输出 dp[1][1] 即可

完整代码

#include <bits/stdc++.h>
using std::cin,std::cout,std::vector,std::array;
#define endl "\n"
#define ALL(x) x.begin(),x.end()
typedef long long ll;
typedef std::pair<int,int> PII;
typedef std::tuple<int,int,int> T3I;

template <typename T>
inline void read(T &x) {
    x=0; bool f=false; char c=getchar();
    while(c<'0'||c>'9'){ if(c=='-') f=true; c=getchar(); }
    while(c>='0'&&c<='9'){ x=(x*10)+(c^48); c=getchar(); }
    if(f) x=-x;
}
template <typename T, typename ...Args>
inline void read(T &tmp,Args &...tmps){ read(tmp); read(tmps...); }

std::vector<bool>vis;
std::vector<long long>prime;
auto init=[]{
    int n=1e5;
    vis.resize(n+1,true);
    vis[1]=false;
    for(int i=2;i<=n;++i){
        if(vis[i]) prime.emplace_back(i);
        for(auto &j:prime){
            if(i*j>n) break;
            vis[i*j]=false;
            if(i%j==0) break;
        }
    }
    return 0;
}();

void solve()
{
    int n,m; read(n,m);
    vector<vector<int>>adj(n+1,vector<int>(m+1));
    for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) read(adj[i][j]);
    vector<vector<int>>dp(n+1,vector<int>(m+1,1e9));
    dp[n][m]=0;
    vector<int>minDis(int(1e5)+1,100000);
    for(int i=n;i;--i) for(int j=m;j;--j){
        if(i<n) dp[i][j]=std::min(dp[i][j],dp[i+1][j]+1);
        if(j<m) dp[i][j]=std::min(dp[i][j],dp[i][j+1]+1);
        int now=adj[i][j];
        vector<int>dis;
        if(vis[now]) dis.emplace_back(now);
        else{
            for(int k=2;k*k<=now;++k){
                if(now%k) continue;
                dis.emplace_back(k);
                while(now%k==0) now/=k;
            }
            if(now>1) dis.emplace_back(now);
        }
        for(auto &k:dis) dp[i][j]=std::min(dp[i][j],minDis[k]+1);
        for(auto &k:dis) minDis[k]=std::min(minDis[k],dp[i][j]);
    }
    cout<<dp[1][1]<<endl;
}

int main()
{
    int T=1; // read(T);
    while(T--) solve();
    return 0;
}