「联赛测试」叁拾肆

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=\prod p_i^{a_i} \]

则它的约数个数为:

\[\prod (a_i+1) \]

证明:

\(T=12\),可以分解为 \(2^2\times 3^1\)

那么它的约数是选取若干个质因子 \(2\) 和若干个质因子 \(3\) 相乘而的。

\(2\) 可以选 \(0,1,2\) 个, \(3\) 可以选 \(0,1\) 个,以此组合,所以它的约数有 \(6\) 个。

进而推得一个整数 \(T\) 的约数个数为:

\[\prod (a_i+1) \]

证毕。


它的约数和为:

\[\prod \sum_{j}^{a_i}p_i^j \]

证明:

对于每个约数可以表示为:

\[\prod p_i^x\;(x\in [0,a_i]) \]

则约数和为:

\[\sum \prod^{a_i}_{x_i=0}p_i^{x_i} \]

可以转化为:

\[\prod \sum_{j=0}^{a_i}p_i^j \]

证毕。

但是我们要求的是 \(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\)

posted @ 2020-11-20 17:32  Rubyonlу  阅读(151)  评论(1编辑  收藏  举报