CF1464D The Thorny Path
阿新 • • 發佈:2020-12-22
總的方案數是 \(\prod c_i\),\(c_i\) 是置換環大小。
可以發現對於一個置換環 \(p\),交換 \(p_i, p_j\) 會使其分裂成大小為 \(|i - j|\) 和 \(j\) 的環。交換兩個不同環上的元素,會使兩個環合併。因此我們可以在一次操作內使某個置換環分裂成任意大小,或合併兩個環。
注意到對於確定的和 \(n\),我們要儘可能得到大小為 \(3\) 的環。對於 \(3 \mid n\),所有的環大小應該都為 \(3\),對於 \(n \equiv 1 \pmod 3\),會多出一個 \(4\) 或 \(2 + 2\),對於 \(n \equiv 2\pmod 3\)
接下來計算最小操作步數:
對於 \(3 \mid n\),可以直接貪心地分裂出大小為 \(3\) 的環,剩下一些 \(1, 2\) 直接合並。
對於 \(3 \nmid n\),注意到最多需要額外取出一個 \(4\),如果 \(n \ge 7\),那麼取出一個 \(3\) 是不劣的。
現在環的大小在 \([1, 6]\) 之內,那麼就不需要進行復雜的討論了,我們可以直接列舉 \(2\) 或 \(4\) 的所有整數拆分,遞迴地列舉從 \([1, 6]\) 中哪個數拆分出某個數即可。
#include <cstdio> #include <algorithm> using namespace std; const int N = 1000005, M = 1000000007; const int INF = 1000000000; int p[N], pw3[N / 2]; bool vis[N]; int cnt[10]; int opt; int check() { int c1 = cnt[1] + cnt[4], c2 = cnt[2] + cnt[5]; return cnt[4] + cnt[5] + cnt[6] + (c1 < c2 ? c2 : c2 + (c1 - c2) / 3 * 2); } template<class ...Args> int check(int x, Args... args) { int res = INF; for (int i = x; i <= 6; ++i) { if (cnt[i] == 0) continue; --cnt[i]; ++cnt[i - x]; res = min(res, check(args...) + (i > x)); ++cnt[i]; --cnt[i - x]; } return res; } int main() { pw3[0] = 1; for (int i = 1; i <= 500000; ++i) pw3[i] = (pw3[i - 1] * 3LL) % M; int T; for (scanf("%d", &T); T; --T) { int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", p + i); int c3 = n % 3 == 1 ? n / 3 - 1 : n / 3; printf("%lld ", (1LL * pw3[c3] * (n % 3 == 0 ? 1 : n - 3 * c3) % M)); fill(vis + 1, vis + 1 + n, false); fill(cnt, cnt + 7, 0); int res = 0, opt = INF; for (int i = 1; i <= n; ++i) { if (vis[i]) continue; int sz = 1, x = i; vis[i] = true; while (!vis[p[x]]) x = p[x], vis[x] = true, ++sz; while (sz >= 7) sz -= 3, ++res; ++cnt[sz]; } if (n % 3 == 0) opt = check(); else if (n % 3 == 1) { opt = min(opt, check(1, 1, 1, 1) + 2); opt = min(opt, check(1, 1, 2) + 1); opt = min(opt, check(2, 2)); opt = min(opt, check(1, 3) + 1); opt = min(opt, check(4)); } else { opt = min(opt, check(1, 1) + 1); opt = min(opt, check(2)); } printf("%d\n", res + opt); } return 0; }