11.19模拟

T1

基本上跟石子合并一样。区别可能就是需要维护一下当前已有的集合,可以直接用bitset硬上,也可以预处理,数据小基本上没区别。

#include <cstdio>
#include <cstring>
#include <bitset>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 603;
int n, nn, mx;
int a[maxn];
bitset<303> s[maxn][maxn];
int dp[maxn][maxn];
int g[maxn][maxn];
int main() {
	freopen("merge.in", "r", stdin);
	freopen("merge.out", "w", stdout);
	cin >> n;
	nn = n << 1;
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &a[i]);
		a[i + n] = a[i];
		s[i][i][a[i]] = 1;
		s[i + n][i + n][a[i]] = 1;
		g[i][i] = 1;
		g[n + i][n + i] = 1;
		if (a[i] > mx) mx = a[i];
	}
	for (register int len = 2; len <= n; ++len) {
		for (register int l = 1; l + len - 1 <= nn; ++l) {
			register int r = l + len - 1;
			for (register int k = l; k < r; ++k) {
				if (dp[l][k] + dp[k + 1][r] + g[l][k] * g[k + 1][r] > dp[l][r]) {
					dp[l][r] = dp[l][k] + dp[k + 1][r] + g[l][k] * g[k + 1][r];
					s[l][r] = s[l][k] | s[k + 1][r];
				}
			}
			g[l][r] = 0;
			for (register int i = 1; i <= mx; ++i) if (s[l][r][i]) g[l][r]++;
		}
	}
	int ans = 0;
	for (int l = 1; l + n - 1 <= nn; ++l) if (dp[l][l + n - 1] > ans) ans = dp[l][l + n - 1];
	cout << ans << '
';
	return 0;
}

T2

找规律一定要沉住气,不要着急不要慌,把问题考虑全面,只要用心找一定是能找出来的。

按照人类的思维,一定是把所有城镇都堆在一起尽量堆成一个六边形是最优的,计算方式数据范围(N = 6 imes frac{K(K + 1)}{2})已经给了提示了。

通过这个式子你很容易知道当前能堆成的最大六边形的边长是多少,然后把边角料尽量往边上放即可,在边上连续放不会增加答案,但如果在一条新边上放就会使答案+1。

#include <bits/stdc++.h>
using namespace std;

long long n;
inline long long Calc(long long x) {
	return 6 * x * (x + 1) / 2 + 1;
}

int main() {
	freopen("wall.in", "r", stdin);
	freopen("wall.out", "w", stdout);
	cin >> n;
	long long l = 0, r = 1000000000, mid;
	while (l <= r) {
		mid = (l + r) >> 1;
		if (Calc(mid) < n) l = mid + 1;
		else r = mid - 1;
	}
	long long len = l + 1;
	if (n == 6 * len * (len - 1) / 2 + 1) {
		printf("%lld
", len * 6);
		return 0;
	}
	long long ans = (len - 1) * 6 + 1;
	long long res = 6 * (len - 2) * (len - 1) / 2 + 1;
	ans += (n - res) / (len - 1);
	cout << ans << '
';
	return 0;
}

T3

首先考虑 (f_i leq i) 的情况。

#include <bits/stdc++.h>
using namespace std;
#define int long long
inline int read() {
	int s = 0, w = 1;
	char c = getchar();
	while (c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
	while (c >= '0' && c <= '9') s = s * 10 + c - '0', c = getchar();
	return s * w;
}
const int maxn = 1e5 + 10;
struct edge {
	int nex;
	int to;
} e[maxn << 1];
int n;
int tot;
int a[maxn];
int c[maxn];
int d[maxn];
int f[maxn];
int mx[maxn];
int cmx[maxn];
int head[maxn];
void Add(int u, int v) {
	e[++tot] = (edge) { head[u], v }, head[u] = tot;
}
int dfsclock;
int scc;
int top;
int stk[maxn];
int dfn[maxn];
int low[maxn];
int bel[maxn];
int siz[maxn];
int from[maxn];
bool vis[maxn];
vector<int> hav[maxn];
void Tarjan(int u) {
	dfn[u] = low[u] = ++dfsclock;
	stk[++top] = u;
	for (int i = head[u]; i; i = e[i].nex) {
		int v = e[i].to;
		if (!dfn[v]) {
			Tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if (!bel[v]) low[u] = min(low[u], dfn[v]);
	}
	if (dfn[u] == low[u]) {
		scc++;
		while (true) {
			int x = stk[top--];
			hav[scc].push_back(x);
			bel[x] = scc;
			siz[scc]++;
			if (u == x) break;
		}
	}
}
signed main() {
	freopen("goods.in", "r", stdin);
	freopen("goods.out", "w", stdout);
	n = read();
	for (int i = 1; i <= n; ++i) {
		from[i] = i;
		f[i] = read(), c[i] = read(), d[i] = read(), a[i] = read();
	}
	for (int i = 1; i <= n; ++i) {
		int v = f[i];
		if (d[v] - c[i] > mx[v]) from[v] = i, cmx[v] = mx[v], mx[v] = d[v] - c[i];
		else if (d[v] - c[i] > cmx[v]) cmx[v] = d[v] - c[i];
	}
	for (int i = 1; i <= n; ++i) Add(from[i], i);
	for (int i = 1; i <= n; ++i) if (!dfn[i]) Tarjan(i);
	int ans = 0;
	for (int i = 1; i <= scc; ++i) {
		if (siz[i] == 1) {
			ans += a[hav[i][0]] * mx[hav[i][0]];
			continue;
		}
		int res = INT_MAX;
		int tmp = 0;
		for (int j = 0; j < (int) hav[i].size(); ++j) {
			int x = hav[i][j];
			tmp += mx[x] * a[x];
			if (mx[x] - cmx[x] < res) res = mx[x] - cmx[x];
		}
		ans += tmp - res;
	}
	cout << ans << '
';
	return 0;
}

T4

暴力就是(n^2)枚举答案,然后dfs暴力删,如果能删完整个串即为答案。别人这么写都是50分,不知道为啥我是20分,可能是没剪枝的问题。

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn = 1e5 + 10;
const int base = 31;
const int mod1 = 998244353;
const int mod2 = 1000000007;
int n;
char s[maxn];
bool del[maxn];
int stk[maxn * 500];
int top;
bool dfs(int cnt, ull now, int len) {
	if (!cnt) return 1;
	int flag = 0;
	for (int l = 1, r; l <= n; ++l) {
		if (del[l]) continue;
		int rcnt = 0;
		ull res = 0;
		r = l;
		int rcd = top;
		while (rcnt < len && r <= n) {
			while (del[r] && r <= n) r++;
			if (r > n) break;
			res = res * base + s[r] - 'a' + 1;
			stk[++top] = r;
			rcnt++;
			if (rcnt < len) r++;
		}
		if (r > n || rcnt < len) {
			while (top > rcd) top--;
			break;
		}
		if (res == now) {
			for (register int i = rcd + 1; i <= top; ++i) del[stk[i]] = 1;
			flag |= dfs(cnt - len, now, len);
			while (top > rcd) del[stk[top--]] = 0;	
		}
		else {
			while (top > rcd) top--;
		}
	}
	return flag;
}
int main() {
	freopen("string.in", "r", stdin);
	freopen("string.out", "w", stdout);
	int T;
	cin >> T;
	while (T--) {
		memset(del, 0, sizeof del);
		scanf("%s", s + 1);
		n = strlen(s + 1);
		register int flag = 0;
		register int L = 0, R = 0;
		for (register int len = 1; len <= n; ++len) {
			ull res = 0;
			ull tmp = 0;
			for (register int l = 1; l + len - 1 <= n; ++l) {
				register int r = l + len - 1;
				res = 0;
				for (int i = l; i <= r; ++i) res = res * base + s[i] - 'a' + 1;
				register int op = 0;
				op |= dfs(n, res, len);
				if (op && !flag) { flag = 1, tmp = res, L = l, R = r; }
				else if (op && flag && tmp > res) { res = tmp, L = l, R = r; }
			}
			if (flag) break;
		}
		if (flag) {
			for (register int i = L; i <= R; ++i) printf("%c", s[i]);
		}
		cout << '
';
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Zfio/p/14005332.html