E. Nearest Opposite Parity
题意:对于每个位置的数i,如果i-a[i]>=1,那么我们就能跳到下表为i-a[i]的位置,如果i+a[i]<=n,那么我们就能跳到下标为i+a[i]的位置;我们需要求出对于每个位置的数,我们进行着两种操作的最小的次数到达与当前数奇偶性相反的数,如果不能达到输出-1。
题解:一开始想当然,暴力bfs,直接就给我超时了,然后想怎么剪枝,想了一个假的剪枝的方法。然后正确的题解,对于每个位置的数跑最短路,每个位置的数一次最多到达两个点,那么就相当于给图上的点连边,然后就是求以这个点为起点到达与这个点奇偶性相反的点的最短距离,我们维护dp[i][0]代表下表为i的数到达奇数的最短距离,dp[i][1]代表到达偶数的最短距离,那么我们反向建图,反向建图就是能求这个点能到达的点往自己的最短路。
#include<bits/stdc++.h>
#define mk make_pair
using namespace std;
const int maxn = 2e5+10;
int a[maxn],dp[maxn][2];
vector<int>G[maxn];
queue<pair<int,int>> q;
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
dp[i][0] = dp[i][1] = -1;
dp[i][a[i]%2] = 0;
q.push(mk(i,a[i]%2));
for(int x:{i-a[i],i+a[i]})
if(x>=1&&x<=n)
G[x].push_back(i) ;
}
while(!q.empty())
{
pair<int,int> tmp = q.front();
q.pop();
for(auto v:G[tmp.first])
if(v>0&&v<=n&&dp[v][tmp.second]==-1)
{
dp[v][tmp.second] = dp[tmp.first][tmp.second] + 1;
q.push(mk(v,tmp.second));
}
}
for(int i=1;i<=n;i++) printf("%d ",dp[i][1-a[i]%2]);
puts("");
}