「联赛测试」叁拾肆
666
用类似与 \(BFS\) 的思想,从 \(1\) 个 \(6\) 的状态向其他状态转移。
记一个当前走了 \(tmp\) 步,对于每个已经可以到达的状态向下转移,直到 \(f[n]\neq -1\) 。
暴力扫发现,最多会走 \(48\) 步,所以只用转移 \(1\sim n+48\) 的状态。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 2e6 + 50, INF = 0x3f3f3f3f;
inline int read () {
register int x = 0, w = 1;
register char ch = getchar ();
for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
return x * w;
}
inline void write (register int x) {
if (x / 10) write (x / 10);
putchar (x % 10 + '0');
}
int n, m, tmp, f[maxn];
inline void Init () {
memset (f, -1, sizeof f), f[1] = 0;
while (f[n] == -1) {
tmp ++;
for (register int i = 1; i <= m; i ++) {
if (f[i] == -1) continue;
register int j = i + i * (tmp - f[i] - 1);//复制粘贴
if (j <= m && j >= 1 && f[j] == -1) f[j] = tmp;
if (f[i - 1] == -1) f[i - 1] = f[i] + 1;//退格
}
}
}
int main () {
freopen ("six.in", "r", stdin);
freopen ("six.out", "w", stdout);
n = read(), m = n + 48, Init (), printf ("%d\n", f[n]);
return 0;
}
春思
还是比较数学的,逼得我直接考场现推约数和定理,印象 \(++\),然后因为不会质因数分解而劝退。
约数和定理
对于一个整数 \(T\),设可以分解质因数为:
则它的约数个数为:
证明:
设 \(T=12\),可以分解为 \(2^2\times 3^1\) 。
那么它的约数是选取若干个质因子 \(2\) 和若干个质因子 \(3\) 相乘而的。
而 \(2\) 可以选 \(0,1,2\) 个, \(3\) 可以选 \(0,1\) 个,以此组合,所以它的约数有 \(6\) 个。
进而推得一个整数 \(T\) 的约数个数为:
证毕。
它的约数和为:
证明:
对于每个约数可以表示为:
则约数和为:
可以转化为:
证毕。
但是我们要求的是 \(a^b\) 的约数和,可以直接将 \(a\) 质因数分解,将每个质因数的次幂都乘上 \(b\),再用约数和定理求。
至于中间的 \(\sum_{j=0}^{a_i}p_i^j\),直接用等比序列求和公式求就行了。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
typedef long long ll;
using namespace std;
const int maxn = 1e6 + 50, INF = 0x3f3f3f3f, mod = 9901;
inline ll read () {
register ll x = 0, w = 1;
register char ch = getchar ();
for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
return x * w;
}
inline void write (register int x) {
if (x / 10) write (x / 10);
putchar (x % 10 + '0');
}
ll a, b, aa, cnt, ans = 1ll;
ll prime[maxn], num[maxn];
inline ll qpow (register ll a, register ll b) {
register ll ans = 1ll;
while (b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod, b >>= 1;
}
return ans;
}
int main () {
freopen ("spring.in", "r", stdin);
freopen ("spring.out", "w", stdout);
a = read(), b = read(), aa = sqrt (a);
for (register ll i = 2; i <= aa; i ++) {
if (a % i == 0) {
prime[++ cnt] = i % mod;
while (a % i == 0) num[cnt] ++, a /= i;
}
}
if (a != 1) prime[++ cnt] = a % mod, num[cnt] ++;
for (register int i = 1; i <= cnt; i ++) {
if (prime[i] == 1) ans = ans * (num[i] * b % mod + 1) % mod; //prime[i] % 9901 = 1 的特判
else ans = ans * (qpow (prime[i], num[i] * b + 1) - 1ll) % mod * qpow (prime[i] - 1, mod - 2) % mod;
}
printf ("%lld\n", ans);
return 0;
}
密州盛宴
先假设只让乡亲们吃 \(0\),不允许他们吃 \(1\),这样放的话显然是合法的,只是会有多余的步数,现在求出来的最多步数是 \(max(num[1] - num[0] -1)\) 。
考虑去掉多余的步骤,我们会发现,\(1\) 比 \(0\) 多余的部分是可以让苏东坡和乡亲们一起吃的,所以可以尽量放到前面,把我们换过去的 \(0\) 换回来,但是放完这多余的,一定要放一个 \(0\),便是最短的距离,即最多步数减去 \(num[1] - num[0]\)。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int maxn = 1e6 + 50, INF = 0x3f3f3f3f;
inline int read () {
register int x = 0, w = 1;
register char ch = getchar ();
for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
return x * w;
}
inline void write (register int x) {
if (x / 10) write (x / 10);
putchar (x % 10 + '0');
}
int n, m, num0, num1, ans;
signed main () {
freopen ("meal.in", "r", stdin);
freopen ("meal.out", "w", stdout);
while (1) {
n = read(), m = read(), ans = num0 = num1 = 0;
if (!n && !m) break;
while (m --) {
register char str[maxn];
scanf ("%s", str + 1);
register int tmp0 = 0, tmp1 = 0, maxx = 0, t = read(), len = strlen (str + 1);
for (register int i = 1; i <= len; i ++) {
if (str[i] == '0') tmp0 ++;
else tmp1 ++;
maxx = max (maxx, tmp1 - tmp0);
}
if (tmp1 > tmp0) ans = max (ans, (num1 + tmp1 * (t - 1)) - (num0 + tmp0 * (t - 1)) + maxx - 1);
else ans = max (ans, num1 - num0 + maxx - 1);
num0 += tmp0 * t, num1 += tmp1 * t;
}
if (num0 > num1) puts ("-1");
else printf ("%lld\n", max (ans - num1 + num0, 0ll));
}
return 0;
}
赤壁情
借助 \(next\_permutation\) 和题目中给的 \(random\_shuffle\) 可以水到 \(60\;pts\) 。