ALGORITHM NOTE / ARCHIVE

2025 National Invitational of CCPC (Fujian), The 12th Fujian Collegiate Programming Contest——H

  • 多走长度的偶数部分可以忽略,我可以通过在一个点来回走都掉这一部分
  • 设 是我要走的长度,题目条件转化为 ,那么我们的答案就是最小的

补题链接点这里 文章插图 首先可以观察到的是

  • 多走长度的偶数部分可以忽略,我可以通过在一个点来回走都掉这一部分
  • 设 是我要走的长度,题目条件转化为 ,那么我们的答案就是最小的

如何判定是否有解,这里需要通过 和我可以走的步数 的奇偶性进行判定,这里我现根据奇偶最短路的情况,再根据 是否等于 的情况来做分类

首先特判掉图不连通的情况,

如果只有奇最短路 ,

如果 的情况下,我们另 ,计算差值

  • 是奇数并且 是奇数 ,那么答案是 我需要额外一步让多出来的部分是偶数。如果l是偶数,那么无解。
  • 是偶数,答案就是

如果 ,那么答案是

如果只有偶最短路的情况是同理的,可以自己推理或者看我代码

如果奇最短路和偶最短路都有,那么对奇最短路和偶最短路都尝试一下,答案取min

VP的时候写的,有点凌乱,见谅

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;
#define int long long

constexpr int N = 1024;
constexpr int inf = 1e9;
constexpr array<int,8> dx={-1,-1,-1,0,0,1,1,1};
constexpr array<int,8> dy={1,0,-1,1,-1,1,0,-1};
int n,m,l,r;
char mp[N][N];
int dis[N][N][2];
bool vis[N][N][2];
void solve(){
    cin>>n>>m;
    cin>>l>>r;
    for(int i = 1;i<=n;++i){
        for(int j =1;j<=m;++j){
            cin>>mp[i][j];
            dis[i][j][0] = dis[i][j][1] = inf;
            vis[i][j][0]=vis[i][j][1]=0;
        }
    }

    auto check=[&](int x,int y,int z)->bool{
        return (x>=1&&x<=n&&y>=1&&y<=m&&vis[x][y][z]==0&&mp[x][y]=='1');
    };
    dis[1][1][0]=0;
    queue<array<int,3>> q;
    vis[1][1][0]=1;
    q.push({1,1,0});
    while(!q.empty()){
        auto [x,y,z] = q.front();
        q.pop();
        for(int k = 0;k<8;++k){
            int tx = x+dx[k],ty=y+dy[k],tz = z+1;
            if(check(tx,ty,tz&1)){
                dis[tx][ty][tz&1] = tz;
                vis[tx][ty][tz&1] = 1;
                q.push({tx,ty,tz});
            }
        }
    } 
    array<int,2> mi = {dis[n][m][0],dis[n][m][1]};
    if(mi[0]>=inf&&mi[1]>=inf){
        cout<<"-1\n";
        return;
    }else if(mi[0]>=inf){//只有奇最短路
        if(l==r){
            i64 k = (mi[1]+l-1)/l;
            i64 diff = k*l-mi[1];
            if(diff&1){
                if(l&1) cout<<k+1<<"\n";
                else cout<<"-1\n";
            }else{
                cout<<k<<"\n";
            }
        }else{
            cout<<(mi[1]+r-1ll)/r<<"\n";
        }
        return;
    }else if(mi[1]>=inf){//只有偶数最短路
        if(l==r){
            i64 k = (mi[0]+l-1)/l;
            i64 diff = k*l-mi[0];
            if(diff&1){
                if(l&1) cout<<k+1<<"\n";
                else cout<<"-1\n";
            }else{
                cout<<k<<"\n";
            }
        }else{
            cout<<(mi[0]+r-1ll)/r<<"\n";
        }
        return;
    }else{
        if(l==r){
            int ans = 1e9;
            i64 k1 = (mi[0]+r-1ll)/r;
            i64 diff = k1*r-mi[0];
            if(diff%2&&r%2){
                ans = min(ans,k1+1);
            }else if(diff%2==0) ans = min(ans,k1);
      
            i64 k2 = (mi[1]+r-1ll)/r;
            diff = k2*r-mi[1];
            if(diff%2&&r%2){
                ans = min(ans,k2+1);
            }else if(diff%2==0) ans = min(ans,k2);
            if(ans>=inf) cout<<"-1\n";
            else cout<<ans<<"\n";
        }else cout<<min((mi[0]+r-1ll)/r,(mi[1]+r-1ll)/r)<<"\n";
        return;
    }
}

signed main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int t=1;
    cin>>t;
    while(t--) solve();
    return 0;
}