結果
問題 |
No.101 ぐるぐる!あみだくじ!
|
ユーザー |
![]() |
提出日時 | 2014-12-05 22:00:55 |
言語 | C++11(廃止可能性あり) (gcc 13.3.0) |
結果 |
AC
|
実行時間 | 2 ms / 5,000 ms |
コード長 | 2,056 bytes |
コンパイル時間 | 616 ms |
コンパイル使用メモリ | 70,284 KB |
実行使用メモリ | 5,376 KB |
最終ジャッジ日時 | 2024-06-11 15:48:26 |
合計ジャッジ時間 | 1,676 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 37 |
ソースコード
//想定解法 ループを回す //1.あみだくじを1回シミュレートして置換先を決定する。 //2.実際にループをn回回して列の一部がもとに戻るために必要な置換の最小回数を検出する。 // たとえば、列の1番目が1->4->3->2->1となったとき、列の1番目は長さ4の巡回置換に属している。 //3.列のそれぞれの要素が属している巡回置換の長さの最小公倍数が答え。 // 計算量はO(n^2 + k)。頑張れば削れそう #include <iostream> #include <vector> #include <map> #include "assert.h" #include <fstream> #include <cstdlib> #include <ctime> #include <sstream> using namespace std; #define MAX_N 100 #define MAX_K 1000 long long gcd(long long a, long long b){ if(b==0) return a; return gcd(b, a%b); } long long lcm(long long a, long long b){ if(a<b) swap(a,b); if(b==1) return a; return a* (b/gcd(a,b)); } int solve_loop(const vector<int> &v){ int n = v.size(); vector<int> pos(n); vector<int> next(n); for(int i=0; i<n; i++) pos[i] = i; vector<int> sub_loop(n, n+100); //実際にn回置換を行う //巡回置換の長さは最大でnなのでn回回せば十分 for(int i=0; i<n; i++){ for(int j=0; j<n; j++){ next[ j ] = pos[ v[j] ] ; } for(int j=0; j<n; j++){ if(next[j] == j){ //列のj番目が初めてjに戻ったときのループ回数 sub_loop[j] = min(sub_loop[j], i+1); } } swap(pos, next); } int ret = 1; for(int i=0; i<n; i++){ ret = lcm(ret, sub_loop[i]); } return ret; } int main(){ int N; cin >> N; assert(2<=N && N<=MAX_N); int K; cin >> K; assert(0<=K && K<=MAX_K); vector<int> v(N); for(int i=0; i<N; i++){ v[i] = i; } for(int i=0; i<K; i++){ int x,y; cin >> x >> y; assert(1<=x && x<= N); assert(1<=y && y<= N); assert(x<y); assert(x+1 == y); x--; y--; swap( v[x], v[y] ); } cout << solve_loop(v) << endl; return 0; }