予鈴

アウトプットとメモ書きの中間みたいな記事がたくさん出ます。

Mujin Contest D - うほょじご

解く前に考えていたこと

・絶対これ考察するだけでしょwと思ってたら違った。
・規則性を見出すことが全くできなかった。シュミレーションの選択肢を除外した。

正解

・解答を見ると閉路を探し出すような解答になっていたが、わからなかったのでメモ化再起で解いた。
 N \leq 999なので、2次元配列で状態を持てる。
・無限ループに突入する部分の判定が勉強になった。

if(visit[x][y] > 0) return true;
        if(visit[x][y] < 0) return false;
        int tx = x,ty = y;
        visit[x][y] = true;
        x < y ? x = rev(x) : y = rev(y);
        x < y ? y = y - x  : x = x - y;
        if(x <= 0 or y <= 0){
            visit[tx][ty] = -1;
            return false;
        }
        visit[tx][ty] = (dfs(x,y) ? 1 : -1);
        return visit[tx][ty] == 1;

まず、x,yに対し、visit[x][y]に1を一時的に格納する。
x,yに対して操作を行った後、閉路に突入する(つまり、x,yに戻ってくる)と、格納されている1が帰る。
そうでない場合は途中で-1に更新され、その組は解になりえない事がわかる。

#include<bits/stdc++.h>
using ll  = long long;
#define int ll

using namespace std;
int rev(int num){
    auto s = to_string(num);
    reverse(begin(s),end(s));
    return stol(s);
}
signed main(){
    int n,m;
    cin >> n >> m;
    int ans = 0;
    vector<vector<int>>visit(1000,vector<int>(1000,0));
    function<bool(int,int)> dfs = [&](int x, int y) -> bool{
        if(visit[x][y] > 0) return true;
        if(visit[x][y] < 0) return false;
        int tx = x,ty = y;
        visit[x][y] = true;
        x < y ? x = rev(x) : y = rev(y);
        x < y ? y = y - x  : x = x - y;
        if(x <= 0 or y <= 0){
            visit[tx][ty] = -1;
            return false;
        }
        visit[tx][ty] = (dfs(x,y) ? 1 : -1);
        return visit[tx][ty] == 1;
    };
    for(int i = n; i >= 1; --i){
        for(int j = m; j >=1;--j){
            ans += dfs(i,j);
        }
    }
    cout << ans << endl;
}