在家看 NOI2024 题面后打的神金代码

Day 1 集合

#include <iostream>
#include <map>
#include <random>
using namespace std;
const int N = 2e5 + 10, M = 6e5 + 10;
int n, m, q, x, y, a[N][3], b[N][3], cur, req[N];
using ull = unsigned long long;
map<ull, int> mp;
random_device rd;
mt19937 mt(rd());
ull sg[N], pa[M], pb[M];
void acs(int x, int v)
{
	for (int i = 0; i < 3; i++)
	{
		cur += !mp[pa[a[x][i]]];
		mp[pa[a[x][i]]]--;
		cur -= !mp[pa[a[x][i]]];
		pa[a[x][i]] += v * sg[x];
		cur += !mp[pa[a[x][i]]];
		mp[pa[a[x][i]]]++;
		cur -= !mp[pb[b[x][i]]];

		cur += !mp[pb[b[x][i]]];
		mp[pb[b[x][i]]]++;
		cur -= !mp[pb[b[x][i]]];
		pb[b[x][i]] += v * sg[x];
		cur += !mp[pb[b[x][i]]];
		mp[pb[b[x][i]]]--;
		cur -= !mp[pb[b[x][i]]];
	}
}
int main()
{
	scanf("%d%d%d", &n, &m, &q);
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			scanf("%d", a[i] + j);
		}
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			scanf("%d", b[i] + j);
		}
	}
	for (int i = 1; i <= m; i++)
	{
		sg[i] = mt();
	}
	for (int i = 1, j = 1; i <= n; i++)
	{
		acs(i, 1);
		while (cur)
			acs(j, -1), j++;
		req[i] = j;
	}
	for (int i = 1; i <= q; i++)
	{
		scanf("%d%d", &x, &y);
		puts(req[y] <= x ? "Yes" : "No");
	}
}

笑点解析:看不懂题解自己重新想了一个哈希方法,以及有一行把 pa 打成 pb 了还能过样例

#include <iostream>
#include <map>
#include <random>
using namespace std;
const int N = 2e5 + 10, M = 6e5 + 10;
int n, m, q, x, y, a[N][3], b[N][3], cur, req[N];
using ull = unsigned long long;
map<ull, int> mp;
random_device rd;
mt19937 mt(rd());
ull sg[N], pa[M], pb[M];
void upd(ull x, int v)
{
	cur += !mp[x];
	mp[x] += v;
	cur -= !mp[x];
}
void acs(int x, int v)
{
	for (int i = 0; i < 3; i++)
	{
		upd(pa[a[x][i]], -1);
		pa[a[x][i]] += v * sg[x];
		upd(pa[a[x][i]], 1);

		upd(pb[b[x][i]], 1);
		pb[b[x][i]] += v * sg[x];
		upd(pb[b[x][i]], -1);
	}
}
int main()
{
	scanf("%d%d%d", &n, &m, &q);
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			scanf("%d", a[i] + j);
		}
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			scanf("%d", b[i] + j);
		}
	}
	for (int i = 1; i <= m; i++)
	{
		sg[i] = mt();
	}
	for (int i = 1, j = 1; i <= n; i++)
	{
		acs(i, 1);
		while (cur)
			acs(j, -1), j++;
		req[i] = j;
	}
	for (int i = 1; i <= q; i++)
	{
		scanf("%d%d", &x, &y);
		puts(req[y] <= x ? "Yes" : "No");
	}
}

笑点解析:封装一个函数后直接省下 \(160\) 字节,而且只有 \(15\)

#include <iostream>
#include <map>
#include <random>
using namespace std;
const int N = 2e5 + 10, M = 6e5 + 10;
int n, m, q, x, y, a[N][3], b[N][3], cur, req[N];
using ull = unsigned long long;
map<ull, int> mp;
random_device rd;
mt19937 mt(rd());
ull sg[N], pa[M], pb[M];
void upd(ull x, int v)
{
	cur += !mp[x];
	mp[x] += v;
	cur -= !mp[x];
}
void acs(int x, int v)
{
	for (int i = 0; i < 3; i++)
	{
		upd(pa[a[x][i]], -1);
		pa[a[x][i]] += v * sg[x];
		upd(pa[a[x][i]], 1);

		upd(pb[b[x][i]], 1);
		pb[b[x][i]] += v * sg[x];
		upd(pb[b[x][i]], -1);
	}
}
int main()
{
	scanf("%d%d%d", &n, &m, &q);
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			scanf("%d", a[i] + j);
		}
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			scanf("%d", b[i] + j);
		}
	}
	for (int i = 1; i <= n; i++)
	{
		sg[i] = mt();
	}
	for (int i = 1, j = 1; i <= n; i++)
	{
		acs(i, 1);
		while (cur)
			acs(j, -1), j++;
		req[i] = j;
	}
	for (int i = 1; i <= q; i++)
	{
		scanf("%d%d", &x, &y);
		puts(req[y] <= x ? "Yes" : "No");
	}
}

笑点解析:这个代码和上一个代码只差一个字母,但是它 \(100\)

Day 2 分数

#include <iostream>
#include <numeric>
#include <set>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
int n, m;
using ll = long long;
struct frac
{
	ll x, y;
	const bool valid() const
	{
		return x > 0 and x <= n and y <= m and (x * 2 <= y or x >= y * 2);
	}
	const frac rev() const
	{
		return {y, x};
	}
	const frac ad(ll v) const
	{
		return {x + v * y, y};
	}
	bool operator<(const frac &ele) const
	{
		if (x != ele.x)
			return x < ele.x;
		return y < ele.y;
	}
};
set<frac> st;
queue<frac> q;
int main()
{
	scanf("%d%d", &n, &m);
	st.insert({1, 2});
	q.push({1, 2});
	while (q.size())
	{
		frac tmp = q.front();
		q.pop();
		for (auto &i : {tmp.rev(), tmp.ad(2), tmp.ad(-2)})
		{
			if (!i.valid() or st.count(i))
				continue;
			st.insert(i);
			q.push(i);
		}
	}
	printf("%d\n", st.size());
	// for (auto &i : st)
	// {
	// 	printf("%lld %lld\n", i.x, i.y);
	// }
}

笑点解析:不剪枝有 \(50\)

#include <iostream>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
int n, m;
using ll = long long;
struct frac
{
	ll x, y;
	const bool valid() const
	{
		return x > 0 and x <= n and y <= m and (x * 2 <= y or x >= y * 2);
	}
	const frac rev() const
	{
		return {y, x};
	}
	const frac ad(ll v) const
	{
		return {x + v * y, y};
	}
	bool operator<(const frac &ele) const
	{
		if (y != ele.y)
			return y < ele.y;
		return x < ele.x;
	}
};
queue<frac> q;
ll res = 2;
int main()
{
	scanf("%d%d", &n, &m);
	q.push({1, 2});
	q.push({2, 1});
	while (q.size())
	{
		frac tmp = q.front();
		q.pop();
		for (auto &i : {tmp.ad(2), tmp.rev().ad(2).rev()})
		{
			if (!i.valid())
				continue;
			res++;
			q.push(i);
		}
	}
	printf("%lld\n", res);
}

笑点解析 \(2\):用了 Calkin-Wilf 树然后不加剪枝就变成了 \(85\)

posted @ 2024-07-21 16:05  丝羽绫华  阅读(33)  评论(0编辑  收藏  举报