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 << '\n';
return 0;
}
T2
找规律一定要沉住气,不要着急不要慌,把问题考虑全面,只要用心找一定是能找出来的。
按照人类的思维,一定是把所有城镇都堆在一起尽量堆成一个六边形是最优的,计算方式数据范围\(N = 6 \times \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\n", 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 << '\n';
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 << '\n';
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 << '\n';
}
return 0;
}
$$We're \; here \; to \; put \; a \; dent \; in \; the \; universe.$$