[ARC112F] Die Siedler - Solution
将整个卡牌序列看作一个「
首先注意到换牌操作是严格不劣的,理解大概就是,因为我们是进位,加牌包就是加法,而最后是最小化位数和,贪心的进位最后一定是不劣的。
我们考虑设
因此对于正整数
那么就考虑只有第一种牌有
这样我们就把初始局面和卡包都转化为了一个数。
还有一点,如果只有
设每个卡包使用了
如果设
系数为
我们并不关心方程的具体解,只关心是否有解。直接使用裴蜀定理,令
设
-
-
G$ 较小,考虑同余最短路,对于 $i \in [0,\,G - 1]$ 连接 $i \to i + 2^ii!$,求 $\text{dist}(S \bmod G)$ 即可,时间复杂度 $\Theta(nG) 。
直接根号分治看起来复杂度是
#include <bits/stdc++.h>
#define X first
#define Y second
#define mp make_pair
#define gc getchar
#define pc putchar
using namespace std;
using ld = double;
typedef long long int ll;
typedef long long int i128;
using pli = pair<ll, int>;
using ppi = pair<pli, int>;
using vec = vector<int>;
constexpr int maxn = 4e6 + 10, S = 4e6, mod = 998244353;
ll gcd(ll n, ll m) { return !m ? n : gcd(m, n % m); }
int q[maxn], d[maxn], hd = 1, tl = 0, n, m; ll a[maxn], p[maxn], G;
inline ll solve(ll x) {
ll sum = 0;
for (int i = 1; i <= n; i++) sum += x % (2 * i), x /= 2 * i;
return sum;
}
int main() {
scanf("%d%d", &n, &m); p[0] = 1;
for (int i = 1; i <= n; i++) p[i] = p[i - 1] * 2 * i; G = p[n] - 1;
for (int i = 0; i <= m; i++) {
for (int j = 1, x; j <= n; j++) {
scanf("%d", &x);
a[i] = a[i] + p[j - 1] * x;
}
}
for (int i = 1; i <= m; i++) G = gcd(G, a[i]);
if (G <= S) {
memset(d, 0x3f, sizeof(d));
for (int i = 1; i <= n; i++) d[q[++tl] = p[i] % G] = 1;
while (hd <= tl) {
int u = q[hd++];
for (int i = 1; i <= n; i++) {
int v = (u + p[i]) % G;
if (d[v] > d[u] + 1) d[q[++tl] = v] = d[u] + 1;
}
}
printf("%d\n", d[a[0] % G]);
}
else {
ll ans = 2e18; ll x = a[0] % G ? a[0] % G : G;
while (x < p[n]) ans = min(ans, solve(x)), x += G;
printf("%lld\n", ans);
}
return 0;
}