
- 正解:线段树优化DP即可,可以做到 \(O(n^2 \log n)\) ,赛时感觉这个比较显然就直接写了。
点击查看代码
#include <bits/stdc++.h>
const int N = 1e3 + 5;
const int M = 1e6 + 5;
using namespace std;
int n, m, ans;
string s1, s2;
vector<int> p[N];
bool vis[N];
int f[N], maxn[M << 2];
void update(int i, int l, int r, int x, int y)
{
if (l == r)
{
maxn[i] = max(maxn[i], y);
return;
}
int mid = (l + r) >> 1;
if (x <= mid)
update(i * 2, l, mid, x, y);
else
update(i * 2 + 1, mid + 1, r, x, y);
maxn[i] = max(maxn[i * 2], maxn[i * 2 + 1]);
}
int query(int i, int l, int r, int x, int y)
{
if (l >= x && r <= y)
return maxn[i];
int mid = (l + r) >> 1, ans = 0;
if (x <= mid)
ans = max(ans, query(i * 2, l, mid, x, y));
if (y > mid)
ans = max(ans, query(i * 2 + 1, mid + 1, r, x, y));
return ans;
}
signed main()
{
freopen("match.in", "r", stdin);
freopen("match.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
cin >> s1 >> s2;
s1 = ' ' + s1;
s2 = ' ' + s2;
for (int i = 1; i <= n; i++)
s1[i] -= 'A' - 1;
for (int i = 1; i <= m; i++)
s2[i] -= 'A' - 1;
for (int i = 1; i <= n; i++)
{
if (vis[s1[i]])
continue;
vis[s1[i]] = 1;
for (int j = 1; j <= m; j++)
if (s1[i] == s2[j])
p[s1[i]].push_back(j);
}
for (int i = 1; i <= n; i++)
{
for (int k = p[s1[i]].size() - 1; k >= max(0, (int)p[s1[i]].size() - 10000); k--)
{
int j = p[s1[i]][k];
if (j == 1)
{
f[i] = max(f[i], 1);
continue;
}
int nw = query(1, 1, m, 1, j - 1) + 1;
f[i] = max(f[i], nw);
update(1, 1, m, j, nw);
}
}
for (int i = 1; i <= n; i++)
ans = max(ans, f[i]);
cout << ans;
}
- 部分分(\(30pts\)):直接跑n遍 dij 。
点击查看代码
#include <bits/stdc++.h>
#define int long long
const int N = 2e5 + 5;
using namespace std;
int n, m, T, ans = 1e18;
int dis[N];
bool vis[N];
vector<pair<int, int>> e[N];
int s[N];
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
void dij(int s)
{
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[s] = 0;
q.push({dis[s], s});
while (q.size())
{
int x = q.top().second;
q.pop();
if (vis[x])
continue;
vis[x] = 1;
for (auto y : e[x])
{
int to = y.first, w = y.second;
if (dis[to] > dis[x] + w)
{
dis[to] = dis[x] + w;
q.push({dis[to], to});
}
}
}
}
signed main()
{
freopen("map.in", "r", stdin);
freopen("map.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m >> T;
for (int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
e[u].push_back({v, w});
e[v].push_back({u, w});
}
for (int i = 1; i <= T; i++)
cin >> s[i];
for (int i = 1; i <= T; i++)
{
dij(s[i]);
for (int j = 1; j <= T; j++)
{
if (i == j)
continue;
ans = min(ans, dis[s[j]]);
}
}
cout << ans;
}
- 正解:建立超级源点找出每个关键点的支配范围(在该范围内的点离该点最近),设答案为 \(dis(u,v)\) ,则存在分界边使得路径上所有边一侧归于 \(u\) 一侧归于 \(v\) ,枚举此关键边即可。
- 乱搞:大力优化部分分做法,加入一系列剪枝,可以爆标。
点击查看代码
#include <bits/stdc++.h>
#define int long long
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
using namespace std;
int n, m, T, ans = inf;
int dis[N];
bool ys[N];
queue<int> vi;
vector<pair<int, int>> e[N];
int s[N];
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
void dij(int s)
{
//memset(dis, 0x3f, sizeof(dis));
//memset(vis, 0, sizeof(vis));
vi.push(s);
dis[s] = 0;
q.push({dis[s], s});
while (q.size())
{
int x = q.top().second;
q.pop();
if (dis[x] >= ans)
continue;
if (x != s && ys[x])
{
ans = dis[x];
continue;
}
for (auto y : e[x])
{
int to = y.first, w = y.second;
if (dis[to] > dis[x] + w)
{
if (dis[to] == inf)
vi.push(to);
dis[to] = dis[x] + w;
if (dis[to] > ans)
continue;
q.push({dis[to], to});
}
}
}
while (!vi.empty())
dis[vi.front()] = inf, vi.pop();
}
signed main()
{
freopen("map.in", "r", stdin);
freopen("map.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m >> T;
for (int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
e[u].push_back({v, w});
e[v].push_back({u, w});
}
memset(dis, 0x3f, sizeof(dis));
for (int i = 1; i <= T; i++)
cin >> s[i], ys[s[i]] = 1;
for (int i = 1; i < T; i++)
dij(s[i]);
cout << ans;
}
点击查看代码
#include <bits/stdc++.h>
#define lowbit(x) (x & -x)
const int N = 5e5 + 5;
using namespace std;
int T, L, R, ans;
string ll, rr;
int tot, a[N];
// void update(int x, int val)
// {
// for (int i = x; i <= tot; i += lowbit(i))
// t[i] += val;
// }
// int query(int x)
// {
// int sum = 0;
// for (int i = x; i >= 1; i -= lowbit(i))
// sum += t[i];
// return sum;
// }
void solve()
{
//cerr << 999;
for (int i = 1; i <= tot; i++)
{
for (int j = i + 1; j <= tot; j++)
ans += (a[i] > a[j]);
}
// cerr << ans << '\n';
}
void work(int x)
{
//cerr << x;
tot = 0;
while (x)
a[++tot] = x % 10 + 1, x /= 10;
reverse(a + 1, a + tot + 1);
//for (int i = 1; i <= tot; i++)
// cerr << a[i] << ' ';
//cerr << '\n';
solve();
}
signed main()
{
freopen("bubble.in", "r", stdin);
freopen("bubble.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while (T--)
{
ans = 0;
L = 0;
R = 0;
cin >> ll >> rr;
if (ll == rr)
{
tot = 0;
for (auto i : ll)
a[++tot] = (i - '0');
solve();
cout << ans << '\n';
continue;
}
for (int i = ll.size() - 1; i >= 0; i--)
L += (ll[i] - '0') * pow(10, ll.size() - i - 1);
for (int i = rr.size() - 1; i >= 0; i--)
R += (rr[i] - '0') * pow(10, rr.size() - i - 1);
//cerr << L << R;
for (int i = L; i <= R; i++)
work(i);
cout << ans << '\n';
}
}
- 正解:神秘数位 DP ,不会。粘题解了,
虽然题解写的壱陀矢根本不知所云。

总结
- 困
- 实际上写完 T2 部分分就摆了,没有尝试很显然的乱搞。
- 后两个小时完全不知道自己在干什么,全是垃圾时间。