Problem:
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}
});

H: ジャンプパーティ

問題

とあるダンスホールで $N$ 人の参加するダンスパーティーが行われる。
そのダンスホールは縦方向に $H$ 個、横方向に $W$ 個のグリッドに分けられており、
左上を $(0,0)$、上から $r$ マス、左から $c$ マス目のグリッドの座標を $(r,c)$ と表す。
$i$ 番目の参加者の初期位置は $(R_i, C_i)$ であり、$(i,j)$ のグリッドには $(r_{ij}, c_{ij})$ が書かれている。

各参加者は、無限に続く音楽に合わせて次のように同時に移動を行う。

その時にいる座標が $(i,j)$ のとき、$(r_{ij}, c_{ij})$ へジャンプで移動する。

それぞれのグリッドは狭く、2 人以上の参加者が同時に同じグリッドに移動すると衝突してしまう。ただし、空中で衝突することは無いとする。
これを聞いたあなたは、ジャンプ後に 2 人以上の参加者が衝突してしまわないかと心配になった。
そこで、衝突が起こる可能性があるか、あるならば何回目のジャンプの後に衝突が起こるかを求めることにした。

制約

$1 \le H,W \le 500$

$0 \le N \le H \times W$

$0 \le r_{ij} < H \ (0 \le i < H, 0 \le j < W)$

$0 \le c_{ij} < W \ (0 \le i < H, 0 \le j < W)$

$0 \le R_i < H \ (0 \le i < N)$

$0 \le C_i < W \ (0 \le i < N)$

参加者の初期位置は相異なる

入力形式

入力は以下の形式で与えられる。

$H \ W \ N$

$r_{00} \ c_{00} \ \cdots \ r_{0 \ W-1} \ c_{0 \ W-1}$

$\vdots$

$r_{H-1 \ 0} \ c_{H-1 \ 0} \ \cdots \ r_{H-1 \ W-1} \ c_{H-1 \ W-1}$

$R_0 \ C_0$

$\vdots$

$R_{N-1} \ C_{N-1}$

この問題では入力ファイルが非常に大きくなることがあることに注意せよ。
C++ ならこのページを参考にすると良いかもしれない。

出力

衝突が起こる場合は何回目のジャンプの後に起こるかを 1 行で出力せよ。
そうでない場合は -1 を出力せよ。
また、末尾に改行を出力せよ。

サンプル

サンプル入力 1

2 2 2
1 0 0 1
0 0 1 0
0 0
0 1

サンプル出力 1

-1

サンプル入力 2

2 2 2
1 0 0 1
0 0 1 0
0 0
1 1

サンプル出力 2

1

Solution in C++11 (judge verdict: Accepted)

#include<bits/stdc++.h>
using namespace std;

#define int long long

#define rep(i,n) for(int i=0;i<(n);i++)
#define all(v) (v).begin(),(v).end()
#define pb push_back
typedef vector<int>vint;
typedef pair<int,int>pint;
typedef vector<pint>vpint;
#define fi first
#define se second
template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}

int H,W,N;
int M;
int to[500*500];

int id[500*500];

vector<vint>loop;

void findLoop(){
    vector<int>deg(H*W);
    queue<int>que;
    fill_n(id,500*500,-2);
    rep(i,M)deg[to[i]]++;
    rep(i,M)if(deg[i]==0)que.push(i),id[i]=-1;
    while(que.size()){
        int v=que.front();
        que.pop();
        int u=to[v];
        if(--deg[u]==0){
            id[u]=-1;
            que.push(u);
        }
    }

    rep(i,M){
        if(id[i]!=-2)continue;
        loop.pb(vint());
        int v=i;
        while(id[v]==-2){
            id[v]=loop.size()-1;
            loop.back().pb(v);
            v=to[v];
        }
    }
}

vint T[500*500];
int ans;

int dep[500*500];
set<int>ds[500*500];
bool ex[500*500];
void dfs(int v,int d){
    dep[v]=d;
    if(ex[v])ds[v].insert(d);
    for(auto u:T[v]){
        dfs(u,d+1);
        if(ds[v].size()<ds[u].size())swap(ds[v],ds[u]);
        for(auto it=ds[u].begin();it!=ds[u].end();it++){
            if(ds[v].find(*it)!=ds[v].end()){
                chmin(ans,*it-d);
            }
            ds[v].insert(*it);
        }
    }
}

bool C(int t){
    for(auto &vs:loop){
        vint cnt(vs.size());
        rep(i,vs.size()){
            for(auto u:ds[vs[i]]){
                if(u>t)continue;
                cnt[(i+t-u)%vs.size()]++;
            }
        }
        rep(i,vs.size())if(cnt[i]>1)return true;
    }
    return false;
}

signed main(){
    scanf("%lld%lld%lld",&H,&W,&N);
    M=H*W;
    rep(i,H){
        rep(j,W){
            int a,b;
            scanf("%lld%lld",&a,&b);
            to[i*W+j]=a*W+b;
        }
    }
    vint vs;
    rep(i,N){
        int a,b;
        scanf("%lld%lld",&a,&b);
        vs.pb(a*W+b);
        ex[a*W+b]=1;
    }

    findLoop();

    rep(i,M){
        if(id[i]!=-1)continue;
        T[to[i]].pb(i);
    }

    ans=INT_MAX;

    rep(i,M){
        if(id[i]==-1)continue;
        dfs(i,0);
    }

    int lb=0,ub=INT_MAX;
    while(ub-lb>1){
        int mid=(ub+lb)/2;
        if(C(mid))ub=mid;
        else lb=mid;
    }

    chmin(ans,ub);
    if(ans==INT_MAX)cout<<-1<<endl;
    else cout<<ans<<endl;
    return 0;
}