「MX-X5 / GFOI Round 1」T7 Der Richter 题解
EuphoricStar · · 题解
首先考虑怎么对一个极好的排列
枚举一个正整数
那么交换这个排列使得
交换这个排列使其变成好的的最小操作次数就是对于所有可能的
因为
把这个
考虑把
因为
现在我们的问题是要在其开头添加最少个数的
结论:设这个
注意到只有
可以使用哈希表存储所有形如
时间复杂度
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef __int128 lll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 85;
const int P = 5000011;
ll n, m, mod, a[maxn], fac[maxn], inv[maxn], b[maxn];
__gnu_pbds::gp_hash_table<ll, lll> mp[maxn];
void dfs(int s, int lst, ll res, lll x) {
if (s) {
ll re = res * fac[s] % mod;
int t = s - (m + lst) + 2;
mp[m + lst + t * 2][re] = (x << t) | ((((lll)1) << t) - 1);
}
for (int i = lst; s + i <= 79; ++i) {
if (2 * (s + i) - (m + 1 + i) + 4 > 80) {
continue;
}
a[++m] = i;
ll r = res;
for (int j = 1; j <= i; ++j) {
r = r * inv[i - j + (++b[j])] % mod;
}
dfs(s + i, i, r, ((x << (a[m] - a[m - 1])) | ((((lll)1) << (a[m] - a[m - 1])) - 1)) << 1);
for (int j = 1; j <= i; ++j) {
--b[j];
}
--m;
}
}
inline void init() {
fac[0] = 1;
for (int i = 1; i <= 80; ++i) {
fac[i] = fac[i - 1] * i % mod;
}
inv[1] = 1;
for (int i = 2; i <= 80; ++i) {
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
dfs(0, 1, 1, 0);
}
void solve() {
scanf("%lld%lld", &n, &m);
if (m == 1) {
for (int i = 1; i <= n; ++i) {
printf("%d%c", i, " \n"[i == n]);
}
return;
}
for (int i = n; i >= 2; --i) {
if (mp[i].find(m) != mp[i].end()) {
lll x = mp[i][m];
ll t = n;
for (int j = 1; j <= n; ++j) {
if ((x >> (n - j)) & 1) {
a[j] = (t--);
}
}
for (int j = 1; j <= n; ++j) {
if (((~x) >> (n - j)) & 1) {
a[j] = (t--);
}
}
for (int j = 1; j <= n; ++j) {
printf("%lld%c", a[j], " \n"[j == n]);
}
return;
}
}
puts("-1");
}
int main() {
int T = 1;
scanf("%d%lld", &T, &mod);
init();
while (T--) {
solve();
}
return 0;
}