競プロ覚書

思考整理

ABC195 - E Lucky 7 Battle

atcoder.jp
ゲーム系。
勝負が確定している後ろからDPする(バックトラックというらしい)
この方針は正しかったが、7の倍数判定を無駄に考えすぎて解けず。

【問題】
数列が与えられる。
文字列の手番に従って、高橋君と青木君は新しい数列の末尾にS[i]か0を加える。
最終的に出来た数列が7の倍数なら高橋君の勝ち。
お互い最適に動いたとき、高橋君はゲームに勝てるか?
【典型ポイント】
バックトラック
10の階乗のmodを前計算する
倍数系の問題は都度modを取りながら進められる
【方針】
以下のようなDPテーブルを作る
dp[i][mo]:= i手目まで進んだ時の、余りがmoである場合に高橋君が勝てるかどうか
メモ化でDPする方法が分からなかったので他の人のコードを真似した。書けるようになると楽かもしれない

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pll = pair<long long, long long>;
constexpr char ln =  '\n';
constexpr long long MOD = 1000000007;
constexpr long long INF = 1000000000 + 100;
constexpr long long LINF = 1000000000000000000 + 100;
#define all(v) v.begin(), v.end()
#define rep(i, n) for(int i=0;i<(n);i++)
#define rept(i, j, n) for(int i=(j); i<(n); i++)
#define rrep(i, n) for(int i=(n); i>=0; i--)
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }

int p[201010]; //10の階乗 mod 7
bool memo[201010][7], seen[201010][7];
int main(){
    int N; string S, X; cin >> N >> S >>X;

    p[0] = 1; rept(i, 1, 201010)p[i]= (p[i-1] * 10) % 7;

    //メモ化再帰
    //func(i, mo):=i回目の操作が確定していて、確定している数字を7で割った余りがmoのとき、高橋君の勝ち状態であるか
    auto func = [&](auto&& self, int i, int mo) -> bool{
        if(i==N)return mo == 0;

        if(seen[i][mo])return memo[i][mo];
        seen[i][mo] = true;

        if(X[i] == 'T'){
            //add S[i]
            if(self(self, i+1, (mo + (S[i] - '0') * p[N-i-1]) % 7)) return memo[i][mo] = true;
            //add 0
            if(self(self, i+1, mo))return memo[i][mo] = true;

            return memo[i][mo] = false;
        }
        else{
            //add S[i]
            if(!self(self, i+1, (mo + (S[i] - '0') * p[N-i-1]) % 7)) return memo[i][mo] = false;
            //add 0
            if(!self(self, i+1, mo))return memo[i][mo] = false;

            return memo[i][mo] = true;
        }
    };
    cout << (func(func, 0, 0) ? "Takahashi" : "Aoki") << ln;
}