[赛记] 多校A层冲刺NOIP2024模拟赛21

送信卒 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,然后每次用乘法原理和加法原理统计一下答案即可;

时间复杂度:Θ(n3),但是发现后面的加法原理可以前缀和优化一下,所以时间复杂度 Θ(n2)

点击查看代码
#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 咋做,我们不妨记 prei 表示数值 i 所对应的位置前面有多少比 i 大的数,那么对于现在来说所有 prei<k 的数都会往前移,并且这些数所对应的子序列形成了一个有序排列

那么我们不妨记一个数为 1 表示这个数的 prek0 表示 pre<k,所以我们只需找出这个数后面的第它的排名个 0,然后减去 k 即可;

具体实现上,我们将询问离线,因为我们要用 pre<k 的数,所以将询问按 k 升序排序,然后动态插入 pre<k 的数,这个可以将原数列按 pre 升序排序后单指针维护;

还要支持查询一个数在现在出现过的数中的排名,这个可以用树状数组维护;

还要支持查询一个数列中第 k0 的位置,这个可以用线段树维护;

注意线段树可以开两倍空间,[1,n] 初始全部为 1[n+1,2n] 初始全部为 0,然后动态插入 0 即可,这样便利了后面的查询;

时间复杂度:Θ(nlogn)

点击查看代码
#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;
}
posted @   Peppa_Even_Pig  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示