SRM517 Div1 Easy CompositeSmash

2015/07/27 (Mon) SRM DP

問題

問題文

$ \newcommand{\lcm}[1]{\operatorname{lcm} #1} $ 2つの整数 $N$, $target$ が与えられる.以降それぞれ $x$,$y$ と呼ぶことにする. ある数 $n$ が合成数の場合,それをスマッシュするとランダムで $p,q$ に割れる. $p,q$ は $n$ の約数であり,$pq=n$ である.素数なら何も起こらない. $x$ から始めて,何度かのスマッシュを繰り返して必ず $y$ を作れるだろうか?

方針

整数論っぽい問題文だが実際はゲーム木探索のようなDP. ある $x$ をスマッシュして $p,q$ に分かれたとすると,$p$ か $q$ のどちらかから始めて必ず $y$ を作れるなら答えは Yes になる. $x$ の全ての分かれ方に対してこの条件を満たせば,どんな分かれ方をしても大丈夫なので Yes. 1つでもだめな組があれば No.ゲームでよくあるメモ化探索で実装する.

実装

char dp[200000];

vector<int> EratosthenesSieve(int n){
    vector<int> ps(n+1);
    loop(i,2,n+1) ps[i] = i;
    for (int i = 2; i*i <= n; ++i)
        if (ps[i])
            for (int j = i*i; j <= n; j+=i)
                ps[j] = 0;
    // ps.erase(remove(all(ps),0), ps.end());
    return ps;
}

auto isp = EratosthenesSieve(100010);

class CompositeSmash {
public:
    int x, y;
    // x -> y
    string thePossible(int x_, int y_) {
        tie(x,y) = tie(x_,y_);
        if(x%y != 0) return "No";
        memset(dp,-1,sizeof dp);
        return rec(x) ? "Yes" : "No";
    }
    bool rec(int k){
        char & res = dp[k];
        if(res != -1) return res;
        if(k == y) res = true;
        else if(isp[k]) res = false;
        else {
            res = true;
            for(int i=2;i*i<=k;i++){
                if(k%i==0 && !rec(k/i) && !rec(i)) res = false;
            }
        }
        return res;
    }
};

大学では試験が終わりました.果たして卒業は確定するのでしょうか…