// [2点swapと操作回数] // i->P_iのグラフを考える。 // i,jを選ぶと、i->P_j, j->P_i に行き先が入れ替わる。それ以外は変わらない。(隣接swap以外なら{i, j}と{P_i, P_j}が排反なため。隣接swapは別途確認。) // i,jを同じサイクルから選ぶとサイクルが分かれる。異なるサイクルから選ぶとサイクルが繋がる。 // 操作回数を最小化するには、i,jを同じサイクルから選び続ける必要がある。また、それで十分。 // ↑この辺の話は、適当な順列(何でもいいが、例えば P = (2 3 4 5 6 1))で実際に試すと予想がつきやすい。定番の考察なので覚えてもよさそう。 // // [余り/GCDなどを考える] // 同じサイクルのなかの mod k が全て一致していれば、サイクルに含まれる頂点数 - 1 だけのダメージが確定する。 // 一致していなければ、好きな値を1つpopできる (自己ループにできる) ので、最後まで「mod kが2種類以上の状態」を保てて、ノーダメージにできる。 // // [k=1,2,…,Nに対応する] // サイクルの最小値が0になるよう値をシフトすると、「すべての頂点がkの倍数なら、ans_kに+C-1を寄与」とできる。(C=サイクルに含まれる頂点数) // サイクルの値の最大公約数をgとするとき、gの「約数」であるようなkについて加算を行えばよい。 // a[g] += C-1 などとしておき、ans[k] = a[k] + a[2k] + a[3k] + ... とすればOK。調和級数でO(NlogN)に抑えられる。 // なお、愚直に加算をして時間のかかるケースがあるのかは…定かではない。 #include #include #define rep(i, n) for(i = 0; i < n; i++) using namespace std; using namespace atcoder; int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b); } int n; int p[200000]; int main() { int i; cin >> n; rep(i, n) { cin >> p[i]; p[i]--; } dsu uf(n); rep(i, n) uf.merge(i, p[i]); vector a(n); for (auto gr: uf.groups()) { int minV = 1e+9; for (int v: gr) minV = min(minV, v); int g = 0; for (int v: gr) g = gcd(g, v - minV); a[g] += (int)gr.size() - 1; } for (i = 1; i < n; i++) { int ans = 0; for (int j = i; j < n; j += i) ans += a[j]; cout << ans << endl; } return 0; }