Wannafly挑战赛2
A Cut
签到题,没啥好说的。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
int a[N], n;
int main() {
cin >> n;
int sum = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
sum += a[i];
}
sort(a + 1, a + n + 1);
long long ans = 0;
for (int i = 1; i < n; i++) {
ans += 1ll*sum;
sum -= a[i];
}
cout << ans << endl;
}
B Travel
题解:
这题有点坑。
刚开始每次询问按照 m m m的所有点建图然后跑迪杰斯特拉,超时, 复杂度是 q ∗ m 2 ∗ l o g ( n ) q * m ^ 2 * log(n) q∗m2∗log(n)
差不多是 2 e 9 2e9 2e9级别的被卡了。
这题可以 s s s到 t t t的求短路,只有三种情况, 要么直线从 s s s到 t t t,要么从 s s s到 1 1 1再从 1 1 1到 n n n, 然后再 n n n到 t t t
还有一种就是,通过这 m m m个点任意一个然后再从 这个点到 t t t
所有可以把有关这 m m m个点全部到所有点的最短距离预处理出来, 然后直接枚举每个点就好了。
最后复杂度为 q ∗ m + m ∗ n ∗ l o n g ( n ) q * m + m * n * long(n) q∗m+m∗n∗long(n)
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 7;
typedef long long ll;
ll n, m, d[N];
ll sum[N];
struct edge{
ll u, v, w;
}e[N];
struct node {
ll to, w;
bool operator < (const node x) const {
return w > x.w;
}
};
int vis[N];
int head[N], top = 1;
struct EDGE {
int to, nxt;
ll w;
}E[3 * N];
void add(int u, int v, int w) {
E[top].to = v;
E[top].w = w;
E[top].nxt = head[u];
head[u] = top++;
}
void add_edge(int u, int v, int w) {
add(u, v, w);
add(v, u, w);
}
vector<int> g;
int get_id(int x) {
return lower_bound(g.begin(), g.end(), x) - g.begin() + 1;
}
ll dist[42][N];
priority_queue<node> q;
void dj(int s, int id) {
q.push({s, 0});
for (int i = 1; i <= n; i++) {
vis[i] = 0;
dist[id][i] = 1e16;
}
dist[id][s] = 0;
while (q.size()) {
node cd = q.top();
q.pop();
if (vis[cd.to]) continue;
vis[cd.to] = 1;
for (int i = head[cd.to]; i; i = E[i].nxt) {
int to = E[i].to;
ll w = E[i].w;
if (dist[id][to] > dist[id][cd.to] + w) {
dist[id][to] = dist[id][cd.to] + w;
q.push({to, dist[id][to]});
}
}
}
}
int main() {
ios::sync_with_stdio(0);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> d[i];
if (i + 1 <= n) {
add_edge(i, i + 1, d[i]);
} else {
add_edge(i, 1, d[n]);
}
}
for (int i = 1; i < n; i++) {
sum[i + 1] = sum[i] + d[i];
}
for (int i = 1; i <= m; i++) {
cin >> e[i].u >> e[i].v >> e[i].w;
g.push_back(e[i].u);
g.push_back(e[i].v);
add_edge(e[i].u, e[i].v, e[i].w);
}
sort(g.begin(),g.end());
g.erase(unique(g.begin(), g.end()), g.end());
for (int i = 1; i <= m; i++) {
dj(e[i].u, get_id(e[i].u));
dj(e[i].v, get_id(e[i].v));
}
int q; cin >> q;
while (q--) {
int x, y; cin >> x >> y;
if (y < x) swap(x, y);
ll ans = sum[y] - sum[x];
ans = min(ans, sum[x] + sum[n] - sum[y] + d[n]);
for (int i: g) {
ans = min(ans, dist[get_id(i)][x] + dist[get_id(i)][y]);
}
cout << ans << endl;
}
}
C Butterfly
题解:
这题可以设 d [ i ] [ j ] d[i][j] d[i][j]从 ( i , j ) (i, j) (i,j)这个位置开始向上做多有多少个连续的 x x x, 设 d l [ i ] [ j ] dl[i][j] dl[i][j]表示从 ( i , j ) (i, j) (i,j)开始是、左上角有多少个连续的, 设 d r [ i ] [ j ] dr[i][j] dr[i][j]为右上角有多少个连续的。
有了这个我们就可以枚举每个位置,求出答案。
#include <bits/stdc++.h>
using namespace std;
const int N = 2007;
char mp[N][N];
int d[N][N], dl[N][N], dr[N][N];
int lmin[N][N], rmin[N][N];
int main() {
// ios::sync_with_stdio(0);
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf(" %c", &mp[i][j]);
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (mp[i][j] == 'X') {
d[i][j] = d[i - 1][j] + 1;
dl[i][j] = dl[i - 1][j - 1] + 1;
} else {
d[i][j] = dl[i][j] = 0;
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = m; j; j--) {
if (mp[i][j] == 'X') {
dr[i][j] = dr[i- 1][j + 1] + 1;
} else {
dr[i][j] = 0;
}
}
}
// cout << dl[5][5] << endl;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
lmin[i][j] = min(d[i][j], dr[i][j]);
rmin[i][j] = min(d[i][j], dl[i][j]);
}
}
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (mp[i][j] != 'X') continue;
if (lmin[i][j] % 2 == 0)lmin[i][j]--;
for (int k = lmin[i][j]; k > ans; k--) {
if (rmin[i][j + k - 1] >= k && k % 2) {
ans = max(ans, k);
break;
}
}
}
}
// if (ans == 1) ans = 0;
cout << ans << endl;
}
D.Delete
题解:
首先是有向无环图, 删掉与这个点相连的所有边, 如何判断 s s s 到 t t t的最短路是多少?
考虑拓扑排序, 如果删掉 x x x点 s s s到 t t t存在最短路,那么一定有一条边再的一个点小于 x x x的拓扑序, 和大于 x x x个拓扑序的点, 反之就不存在最短路。
那么如何查询最短路呢?
可以考虑用线段树。具体看代码吧。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 7;
#define m (l + r) / 2
#define lson 2 * node
#define rson 2 * node + 1
typedef long long ll;
vector<pair<int, ll> > g[N];
int d[N], cat[N], top = 1;
ll tree[4 * N];
void tp(int n) {
queue<int> q;
for (int i = 1; i <= n; i++) {
if (d[i] == 0) {
q.push(i);
}
}
while (q.size()) {
int cd = q.front();
q.pop();
cat[cd] = top++;
for (auto it: g[cd]) {
int to = it.first;
d[to]--;
if (d[to] == 0) {
q.push(to);
}
}
}
}
ll dist[3][N], vis[N];
struct node {
int to;
ll w;
bool operator <(const node x) const {
return w > x.w;
}
};
priority_queue<node> q;
void dj(int s, int n, int id) {
for (int i = 1; i <= n; i++) {
vis[i] = 0;
dist[id][i] = 1e15;
}
q.push({s, 0});
dist[id][s] = 0;
while (q.size()) {
node cd = q.top();
q.pop();
if (vis[cd.to]) continue;
vis[cd.to] = 1;
for (auto it: g[cd.to]) {
int to = it.first;
ll w = it.second;
if (dist[id][to] > dist[id][cd.to] + w) {
dist[id][to] = dist[id][cd.to] + w;
q.push({to, dist[id][to]});
}
}
}
}
void update(ll v, int ql, int qr, int l, int r, int node) {
if (ql > qr) return;
if (ql <= l && qr >= r) {
tree[node] = min(tree[node], v);
return ;
}
if (ql <= m) update(v, ql, qr, l, m, lson);
if (qr > m) update(v, ql, qr, m + 1, r, rson);
}
ll query(int pos, int l, int r, int node) {
if (l == r) {
return tree[node];
}
if (pos <= m) return min(tree[node], query(pos, l, m, lson));
else return min(tree[node], query(pos, m + 1, r, rson));
}
struct edge{
int u, v, w;
} e[N];
int main() {
int n, M, s, t;
scanf("%d %d %d %d", &n, &M, &s, &t);
for (int i = 0; i < 4 * N; i++) {
tree[i] = 1e16;
}
for (int i = 1; i <= M; i++) {
int u, v, w; scanf("%d %d %d", &u, &v, &w);
g[u].push_back({v, w});
d[v]++;
e[i].u = u, e[i].v = v, e[i].w = w;
}
tp(n);
top--;
dj(s, n, 1);
for (int i = 1; i <= n; i++) {
g[i].clear();
}
for (int i = 1; i <= M; i++) {
g[e[i].v].push_back({e[i].u, e[i].w});
}
dj(t, n, 2);
for (int i = 1; i <= M; i++) {
int u = e[i].u, v = e[i].v;
ll w = e[i].w + dist[1][u] + dist[2][v];
// cout << "l = " << cat[u] + 1 << " r = " << cat[v] - 1<< " w = " << w << endl;
update(w, cat[u] + 1, cat[v] - 1, 1, top, 1);
}
int q; scanf("%d", &q);
while (q--) {
int x; scanf("%d", &x);
if (dist[1][x] >= 1e15 || dist[2][x] >= 1e15) {
printf("%lld\n", dist[1][t]);
continue;
}
ll ans = query(cat[x] , 1, top, 1);
if (ans >= 1e15) {
puts("-1");
} else {
printf("%lld\n", ans);
}
}
}