比赛-训练赛 (15 Aug, 2018)

1.) 2357数

单调队列或者搜索都行。

#include <cstdio>
#include <deque>

using namespace std;

typedef long long ll;

deque<ll> A[4];

int main()
{
	ll N, x;
	scanf("%lld", &N);
	x = 1;
	while (x < N) {
		A[0].push_back(x * 2);
		A[1].push_back(x * 3);
		A[2].push_back(x * 5);
		A[3].push_back(x * 7);
		int p = 0;
		for (int i = 1; i <= 3; ++i) {
			if (A[i].front() < A[p].front())
				p = i;
		}
		x = A[p].front();
		for (int i = 0; i <= 3; ++i) {
			if (A[i].front() == A[p].front())
				A[i].pop_front();
		}
	}
	printf("%lld\n", x);
	return 0;
}

2.) 监狱

区间 DP 。枚举区间内第一个被释放的人来转移状态。

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int INF = 1e9;
const int _N = 200;

int A[_N], B[15], f[_N][_N], N, M, ans;
bool mk[_N];

void test()
{
	int cnt = 0;
	for (int i = 1; i <= N; ++i)
		mk[i] = 0;
	for (int i = 1; i <= M; ++i) {
		int j;
		mk[A[B[i]]] = 1;
		for (j = A[B[i]] - 1; j >= 1 && !mk[j]; --j);
		cnt += A[B[i]] - 1 - j;
		for (j = A[B[i]] + 1; j <= N && !mk[j]; ++j);
		cnt += j - 1 - A[B[i]];
	}
	ans = min(ans, cnt);
	return;
}

void fun1()
{
	for (int i = 1; i <= M; ++i)
		B[i] = i;
	ans = INF;
	test();
	while (next_permutation(B + 1, B + 1 + M))
		test();
	printf("%d\n", ans);
	return;
}

int dfs(int l, int r)
{
	if (f[l][r] != -1) {
		return f[l][r];
	}
	if (l == r) {
		return f[l][r] = 0;
	}
	f[l][r] = INF;
	for (int i = l; i <= r; ++i) {
		f[l][r] = min(f[l][r], dfs(l, i) + dfs(i + 1, r) + A[r] - A[l - 1] - 2);
	}
//	printf("[%d, %d] = %d\n", l, r, f[l][r]);
	return f[l][r];
}

int main()
{
	
	scanf("%d%d", &N, &M);
	for (int i = 1; i <= M; ++i) {
		scanf("%d", &A[i]);
	}
	if (N <= 105 && M <= 6) {
		fun1();//O(M! * N * M)
		return 0;
	}
	sort(A + 1, A + 1 + M);
	A[0] = 0, A[M + 1] = N + 1;
	memset(f, -1, sizeof f);
	printf("%d\n", dfs(1, M + 1));
	return 0;
}

3.) lucknum

数位 DP 可以拿到 60 分。注意到 DP 方程和组合数的递推式很像。考虑把 \(n\) 个数位作为球,把这些球扔到 \(m\) 表示 \([0, m-1]\)\(m\) 个数字的桶里去(或分成 \(m\) 份)。扔完后按桶表示的数字大小从小到大排序,把扔到桶内的球对应的数位上的数,设置为桶表示的数字,就得到了一个合理的 lucknum 。桶内可以为空。隔板法搞一下答案就是 \(\left(_{m-1}^{n+m-1}\right)\)

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

typedef long long ll;

ll N, M, P;

ll mont(ll t1, ll t2)
{
	t1 %= P;
	ll t = 1;
	while (t2) {
		if (t2 & 1)
			t = t * t1 % P;
		t2 >>= 1;
		t1 = t1 * t1 % P;
	}
	return t;
}

int main()
{
	ll dn, up;
	scanf("%lld%lld%lld", &N, &M, &P);
	dn = M + N - 1;
	up = M - 1;
	if (up > dn - up)
		up = dn - up;
	ll t0 = 1, t1 = 1;
	for (ll i = 1; i <= up; ++i) {
		t0 = t0 * i % P;
		t1 = t1 * (dn - i + 1) % P;
	}
	printf("%lld\n", t1 * mont(t0, P - 2) % P);
	return 0;
}
posted @ 2018-08-18 15:22  derchg  阅读(104)  评论(0编辑  收藏  举报