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

补题链接点这里
在这里插入图片描述
首先可以观察到的是

  • 多走长度的偶数部分可以忽略,我可以通过在一个点来回走都掉这一部分
  • x x x 是我要走的长度,题目条件转化为 x ∈ [ k ⋅ l , k ⋅ r ] x\in[k\cdot l,k\cdot r] x[kl,kr] ,那么我们的答案就是最小的 k k k

如何判定是否有解,这里需要通过 k ⋅ l − x k\cdot l-x klx 和我可以走的步数 [ l , r ] [l,r] [l,r]的奇偶性进行判定,这里我现根据奇偶最短路的情况,再根据 l l l 是否等于 r r r 的情况来做分类

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

如果只有奇最短路 x x x

如果 l = = r l==r l==r 的情况下,我们另 k = ⌈ x l ⌉ k=\lceil \frac{x}{l}\rceil k=lx ,计算差值 d i f f = k ⋅ l − x diff=k\cdot l-x diff=klx

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

如果 l ≠ r l\ne r l=r ,那么答案是 ⌈ x r ⌉ \lceil \frac{x}{r}\rceil rx

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

如果奇最短路和偶最短路都有,那么对奇最短路和偶最短路都尝试一下,答案取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;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值