补题链接点这里

首先可以观察到的是
- 多走长度的偶数部分可以忽略,我可以通过在一个点来回走都掉这一部分
- 设 x x x 是我要走的长度,题目条件转化为 x ∈ [ k ⋅ l , k ⋅ r ] x\in[k\cdot l,k\cdot r] x∈[k⋅l,k⋅r] ,那么我们的答案就是最小的 k k k
如何判定是否有解,这里需要通过 k ⋅ l − x k\cdot l-x k⋅l−x 和我可以走的步数 [ 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=k⋅l−x
- 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;
}
1854

被折叠的 条评论
为什么被折叠?



