SRM508 Div1Easy DivideAndShift

http://community.topcoder.com/stat?c=problem_statement&pm=11434

全然できなかった。調べたら「DivideとShiftの操作は可換」ということがわかって(証明は知らない)そこからはノーヒントで行けた。これで250ptなんだ…

Shiftは数えるだけなので先にDivideを行う。Divideのやり方は高々、2^(素因数の数)だから全列挙してやればいい。あとは各々についてShiftの回数を求める。のんきに数えてたらTLEしたので剰余で考える必要があるのだが、これが難しかった。右にShiftする場合の式がよくわからなくて、手元のサンプルと帳尻を合わせるように書いたら通った(最悪)

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

class DivideAndShift {
public:
    vector<int> prime_factorization(int n){
        vector<int> v;
        if(n==1) v.push_back(1);
        int i=2;
        while(n>1){
            if(n%i==0){
                n/=i;
                v.push_back(i);
            }else{
                i++;
            }
        }
        return v;
    }

    int getLeast( int N, int M ) {
        // 素因数分解
        auto v=prime_factorization(N);
        int n=v.size();
        // 1にシフトするときの回数
        int ans=min(M-1,N-M+1);
        // 割り方
        for(int j=0;j<(1<<n);j++){
            int tmp=N,divcnt=0;
            for(int k=0;k<n;k++){
                if(j>>k&1){
                    tmp/=v[k];
                    divcnt++;
                }
            }
            int shiftcnt=min((M-1)%tmp,(tmp-M%tmp+1)%tmp);
            ans=min(ans,shiftcnt+divcnt);
        }
        return ans;
    }
};