mayoko’s diary

プロコンとかいろいろ。

SRM 652 div1 easy: ThePermutationGame

div2 medで簡単なバージョンの問題を解いていたので、かなり簡単に感じた。

問題:http://community.topcoder.com/stat?c=problem_statement&pm=13229&rd=16316

解法:結論から言うと、Bob側は1〜Nまでの任意の周期の順列を用意できるので、アリスがf(x) = 1と必ずなるようにするためには、xは1〜Nの最小公倍数の倍数でなければならない。
これがわかれば後は簡単で、それぞれの素因数について、一番乗数が多いものを選んできて、掛け算すれば良い(例えばN=100だったら2の素因数として一番乗数が大きいのは64 = 2^6)
あとは証明。鳩の巣論法によってBobはNより大きい周期を作ることができない。また、BobはN以下の任意の周期を作り出すことができる。例えば、[K, 1, 2, ... K-1, (あと適当)]とすれば周期Kの順列を作り出せる。

以下ソースコード

const int MAX = 100100;
const ll MOD = 1000000007;
bool isPrime[MAX];

void init() {
    for (int i = 0; i < MAX; i++) isPrime[i] = true;
    isPrime[0] = isPrime[1] = false;
    for (int i = 2; i < MAX; i++) {
        if (isPrime[i]) {
            for (int j = 2; j * i < MAX; j++) {
                isPrime[i*j] = false;
            }
        }
    }
}

class ThePermutationGame {
public:
    int findMin(int N) {
        init();
        ll ret = 1;
        for (int i = 2; i < MAX; i++) {
            if (i > N) break;
            if (isPrime[i]) {
                ll now = 1;
                while (now <= N) {
                    now *= i;
                }
                now /= i;
                ret *= now;
                ret %= MOD;
            }
        }
        return (int)ret;
    }
};