送信卒 100pts
直接上小数二分答案,然后check
的时候跑dij
,就没了;
点击查看代码
#include <iostream>
#include <cstdio>
#include <queue>
#include <iomanip>
using namespace std;
int n, m;
int sx, sy, tx, ty;
int a[505][505];
double s;
int id(int x, int y) {return (x - 1) * m + y;
}
struct sss{int t, ne;double w;
}e[500005];
int h[500005], cnt;
void add(int u, int v, double ww) {e[++cnt].t = v;e[cnt].ne = h[u];h[u] = cnt;e[cnt].w = ww;
}
double dis[500005];
bool vis[500005];
void dij(int x) {for (int i = 1; i <= n * m; i++) {dis[i] = 999999999.999999999;vis[i] = false;}priority_queue<pair<double, int>, vector<pair<double, int> >, greater<pair<double, int> > > q;while(!q.empty()) q.pop();q.push({0.0, x});dis[x] = 0.0;while(!q.empty()) {int t = q.top().second;q.pop();if (vis[t]) continue;vis[t] = true;for (int i = h[t]; i; i = e[i].ne) {int u = e[i].t;if (dis[u] > dis[t] + e[i].w) {dis[u] = dis[t] + e[i].w;q.push({dis[u], u});}}}
}
bool ck(double x) {for (int i = 1; i <= n * m; i++) h[i] = 0;cnt = 0;for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {if (a[i][j] == 1) continue;if (j + 1 <= m && a[i][j + 1] != 1) {add(id(i, j), id(i, j + 1), 1);add(id(i, j + 1), id(i, j), 1);}if (i + 1 <= n && a[i + 1][j] != 1) {add(id(i, j), id(i + 1, j), x);add(id(i + 1, j), id(i, j), x);}}}dij(id(sx, sy));if (dis[id(tx, ty)] < s) return false;else return true;
}
int main() {freopen("msg.in", "r", stdin);freopen("msg.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> m;cin >> sx >> sy >> tx >> ty;for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {cin >> a[i][j];}}cin >> s;double l = 0.0;double r = s;double ans = 0.0;while(r - l >= 1e-5) {double mid = (l + r) / 2;if (ck(mid)) {ans = mid;r = mid;} else {l = mid;}}cout << fixed << setprecision(3) << ans;return 0;
}
共轭树图 32pts
赛时不会,所以打了暴力和一个特殊性质32pts;
考虑正解,一般像这种题都是DP;
首先挖掘题目性质,发现选出来的图 $ G $ 中的边在原图中不会出现相交的情况,所以我们可以考虑DP,然后就不会了;
上面的是题解做法,但题解写的太CD了看不懂,所以学了学HDK的搜;
我们发现,图 $ G $ 不同可以是当它上面相同的点的深度不同;
所以我们依据这个可以写搜,终止条件是叶子节点的方案数为 $ 1 $,然后每次用乘法原理和加法原理统计一下答案即可;
时间复杂度:$ \Theta(n^3) $,但是发现后面的加法原理可以前缀和优化一下,所以时间复杂度 $ \Theta(n^2) $;
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const long long mod = 998244353;
int n;
vector<int> v[3005];
int x[5005], y[5005];
long long f[3005][3005];
int fa[5005];
long long ans;
void afs(int x, int f) {fa[x] = f;for (int i = 0; i < v[x].size(); i++) {int u = v[x][i];if (u == f) continue;afs(u, x);}
}
long long dfs(int now, int ldep) {if (v[now].size() == 1) {return f[now][ldep] = ldep;}if (f[now][ldep] != -1) return f[now][ldep];long long sum = 0;if (ldep > 1) {sum = (sum + dfs(now, ldep - 1)) % mod;}int ret = 1;for (int i = 0; i < v[now].size(); i++) {int u = v[now][i];if (u == fa[now]) continue;ret = ret * dfs(u, ldep + 1) % mod;}return f[now][ldep] = (ret + sum) % mod;
}
int main() {freopen("reflection.in", "r", stdin);freopen("reflection.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n;for (int i = 1; i <= n - 1; i++) {cin >> x[i] >> y[i];v[x[i]].push_back(y[i]);v[y[i]].push_back(x[i]);}afs(n, 0);memset(f, -1, sizeof(f));long long ans = 1;for (int i = 0; i < v[n].size(); i++) {int u = v[n][i];ans = ans * dfs(u, 1) % mod;}cout << ans;return 0;
}
摸鱼军训 20pts
直接询问离线 + 暴力模拟20pts;
考虑正解,我们不难发现,对于一个询问 $ (k, x) $ ,如果一个数 $ x $ 的前面比他大的数大于等于 $ k $ 个,那这个数每次只会向前移动 $ 1 $ 次,所以一共向前移动 $ k $ 次,直接输出答案即可;
考虑前面的数小于 $ k $ 咋做,我们不妨记 $ pre_i $ 表示数值 $ i $ 所对应的位置前面有多少比 $ i $ 大的数,那么对于现在来说所有 $ pre_i < k $ 的数都会往前移,并且这些数所对应的子序列形成了一个有序排列;
那么我们不妨记一个数为 $ 1 $ 表示这个数的 $ pre \geq k $ ,$ 0 $ 表示 $ pre < k $,所以我们只需找出这个数后面的第它的排名个 $ 0 $,然后减去 $ k $ 即可;
具体实现上,我们将询问离线,因为我们要用 $ pre < k $ 的数,所以将询问按 $ k $ 升序排序,然后动态插入 $ pre < k $ 的数,这个可以将原数列按 $ pre $ 升序排序后单指针维护;
还要支持查询一个数在现在出现过的数中的排名,这个可以用树状数组维护;
还要支持查询一个数列中第 $ k $ 个 $ 0 $ 的位置,这个可以用线段树维护;
注意线段树可以开两倍空间,$ [1, n] $ 初始全部为 $ 1 $ ,$ [n + 1, 2n] $ 初始全部为 $ 0 $,然后动态插入 $ 0 $ 即可,这样便利了后面的查询;
时间复杂度:$ \Theta(n \log n) $;
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n, m;
int a[500005];
struct sss{int k, x, id;
}d[500005];
int ans[500005], pre[500005], pos[500005];
bool cmpk(sss x, sss y) {return x.k < y.k;
}
int b[500005];
bool cmp(int x, int y) {return pre[x] < pre[y];
}
namespace BIT{inline int lowbit(int x) {return x & (-x);}int tr[500005];void add(int pos, int d) {for (int i = pos; i <= n; i += lowbit(i)) tr[i] += d;}int ask(int pos) {int ans = 0;for (int i = pos; i; i -= lowbit(i)) ans += tr[i];return ans;}
}
namespace SEG{inline int ls(int x) {return x << 1;}inline int rs(int x) {return x << 1 | 1;}struct sss{int l, r, sum;}tr[5000005];inline void push_up(int id) {tr[id].sum = tr[ls(id)].sum + tr[rs(id)].sum;}void bt(int id, int l, int r) {tr[id].l = l;tr[id].r = r;if (l == r) return;int mid = (l + r) >> 1;bt(ls(id), l, mid);bt(rs(id), mid + 1, r);}void add(int id, int pos, int d) {if (tr[id].l == tr[id].r) {tr[id].sum = d;return;}int mid = (tr[id].l + tr[id].r) >> 1;if (pos <= mid) add(ls(id), pos, d);else add(rs(id), pos, d);push_up(id);}int ask(int id, int l, int r) {if (l > r) return 0;if (tr[id].l >= l && tr[id].r <= r) {return tr[id].sum;}int mid = (tr[id].l + tr[id].r) >> 1;if (r <= mid) return ask(ls(id), l, r);else if (l > mid) return ask(rs(id), l, r);else return ask(ls(id), l, mid) + ask(rs(id), mid + 1, r);}int ask_po(int id, int sum) {if (tr[id].l == tr[id].r) return tr[id].l;if (sum <= tr[ls(id)].sum) return ask_po(ls(id), sum);else return ask_po(rs(id), sum - tr[ls(id)].sum);}
}
int main() {freopen("bubble.in", "r", stdin);freopen("bubble.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];pre[a[i]] = BIT::ask(n) - BIT::ask(a[i]);pos[a[i]] = i;BIT::add(a[i], 1);}SEG::bt(1, 1, 2 * n);for (int i = 1; i <= n; i++) {SEG::add(1, i + n, 1);}for (int i = 1; i <= n; i++) b[i] = i;sort(b + 1, b + 1 + n, cmp);for (int i = 1; i <= n; i++) BIT::tr[i] = 0;cin >> m;for (int i = 1; i <= m; i++) {cin >> d[i].k >> d[i].x;d[i].id = i;}sort(d + 1, d + 1 + m, cmpk);int now = 1;for (int i = 1; i <= m; i++) {while(now <= n && pre[b[now]] < d[i].k) {SEG::add(1, pos[b[now]], 1);BIT::add(b[now], 1);now++;}if (pre[d[i].x] >= d[i].k) {ans[d[i].id] = pos[d[i].x] - d[i].k;continue;}int sum = SEG::ask(1, 1, d[i].k);int po = SEG::ask_po(1, BIT::ask(d[i].x - 1) + 1 + sum);ans[d[i].id] = po - d[i].k;}for (int i = 1; i <= m; i++) cout << ans[i] << '\n';return 0;
}