首页 > 其他分享 >[赛记] 多校A层冲刺NOIP2024模拟赛16 && 17

[赛记] 多校A层冲刺NOIP2024模拟赛16 && 17

时间:2024-11-04 09:41:30浏览次数:6  
标签:赛记 17 16 int long 2005 Theta include id

四舍五入 100pts

对于一个数 $ x $ ,可以发现它的答案可以分成两部分,一部分在 $ [2x + 1, n] $ 范围内,一部分在小于它的数的范围内,前者 $ \Theta(1) $ 算,对于后者,我们发现满足这个要求的数 $ y $ 一定有 $ x \mod y < w(x, y) $ ( $ w(x, y) $ 定义为如果 $ x \mod y = 0 $,则 $ w(a, b) = \frac xy - 1 $,否则 $ w(a, b) = \lfloor \frac xy \rfloor $ );

对于每个数,可以处理出所有小于它的满足后者的答案,这个可以差分维护;

复杂度是调和级数的,$ \Theta(n \ln n) $;

点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
int n;
long long a[5000005];
long long w(long long x, long long y) {
	if (x % y == 0) return x / y - 1;
	else return x / y;
}
int main() {
	freopen("count.in", "r", stdin);
	freopen("count.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	long long sum = 0;
	for (long long i = 1; i <= n; i++) {
		for (long long j = i; j <= n; j += i) {
			a[j]++;
			a[j + w(i, 2) + 1]--;
		}
		sum += a[i];
		cout << sum + max(0ll, 1ll * n - 1ll * (2 * i)) << ' ';
	}
	return 0;
}

填算符 10pts

发现 $ \And $ 放前面不劣,所以把所有 $ \And $ 放在前面可以得到一个最大的答案;

考虑顺次倒着填 $ \And $,那么我们只需判断当前所得到的答案与能够忍受的二进制位上的最小答案是否在二进制位上有交集即可;

我们需要维护一段 $ \And $,然后再一段 $ | $,再一个 $ \And $,前面的一段 $ \And $ 直接前缀和维护,中间的一段 $ | $ 用线段树维护即可;

时间复杂度:$ \Theta(n \log n) $;

点击查看代码
#include <iostream>
#include <cstdio>
#include <set>
using namespace std;
int n, k;
long long a[5000005], b[5000005];
long long ans;
set<int> s;
namespace SEG{
	inline int ls(int x) {
		return x << 1;
	}
	inline int rs(int x) {
		return x << 1 | 1;
	}
	struct sss{
		int l, r;
		long long 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) {
			tr[id].sum = a[l];
			return;
		}
		int mid = (l + r) >> 1;
		bt(ls(id), l, mid);
		bt(rs(id), mid + 1, r);
		push_up(id);
	}
	long long 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 main() {
	freopen("bitop.in", "r", stdin);
	freopen("bitop.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> k;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	ans = a[1];
	b[1] = a[1];
	for (int i = 2; i <= n; i++) {
		b[i] = (b[i - 1] & a[i]);
	}
	for (int i = 2; i <= k + 1; i++) {
		ans &= a[i];
	}
	for (int i = k + 2; i <= n; i++) {
		ans |= a[i];
	}
	SEG::bt(1, 1, n);
	int res = k;
	long long now = 0;
	for (int i = n - 1; i >= 1; i--) {
		if (res >= i) break;
		if (res == 0) break;
		now = b[res];
		now = (now | SEG::ask(1, res + 1, i));
		now = (now & a[i + 1]);
		if ((now & ans) == ans) {
			s.insert(i);
			res--;
		} else {
			ans ^= (a[i + 1] & ans);
		}
	}
	for (int i = 1; i <= res; i++) cout << i << ' ';
	for (auto it = s.begin(); it != s.end(); it++) cout << *it << ' ';
	return 0;
}

网格 22pts

DP;

部分分暴搜但是没写?

考虑我们需要维护的东西,有以前的答案,到当前位的末尾的数(不完全)与以前的答案的并,这是一个大体的思路;

考虑先乘再加的性质,我们以加为分割点,把所有的乘算出来相加即可;

所以设 $ f_{i, j}, g_{i, j}, h_{i, j}, w_{i, j} $ 分别表示以前已经确定的答案,最后一个数与前面数的乘积,截止到上一个加号所有数(除了最后一个)的乘积,到 $ (i, j) $ 的路径数,转移分三种情况,具体见代码;

注意最后一个数组,我们要考虑所有路径的和,所以注意在更新 $ h_{i, j} $ 时首先应该乘上 $ w_{i, j} $;

时间复杂度:$ \Theta(nm) $;

点击查看代码
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
const long long mod = 998244353;
int n, m;
char s[2005][2005];
long long f[2005][2005], g[2005][2005], h[2005][2005], w[2005][2005];
int main() {
	freopen("grid.in", "r", stdin);
	freopen("grid.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> s[i][j];
		}
	}
	h[1][1] = 1;
	w[1][1] = 1;
	g[1][1] = (s[1][1] - '0');
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (i == 1 && j == 1) continue;
			f[i][j] = (f[i - 1][j] + f[i][j - 1]) % mod;
			g[i][j] = (g[i - 1][j] + g[i][j - 1]) % mod;
			h[i][j] = (h[i - 1][j] + h[i][j - 1]) % mod;
			w[i][j] = (w[i - 1][j] + w[i][j - 1]) % mod;
			if (s[i][j] == '*') {
				h[i][j] = g[i][j];
				g[i][j] = 0;
			}
			if (s[i][j] == '+') {
				f[i][j] = (f[i][j] + g[i][j]) % mod;
				h[i][j] = w[i][j];
				g[i][j] = 0;
			}
			if (s[i][j] >= '0' && s[i][j] <= '9') {
				g[i][j] = (g[i][j] * 10 % mod + (s[i][j] - '0') * h[i][j] % mod) % mod;
			}
		}
	}
	cout << (f[n][m] + g[n][m]) % mod;
	return 0;
}

矩形 48pts

可以联想到以前做过的找四个顶点不完全相同的矩形个数,此题同理,可以 $ \Theta(nm \log n) $ 做拿到48pts好像可以去掉 $ \log $ 但没有细想

考虑正解,发现有小常数的部分分,于是联想到 $ \Theta(n \sqrt n) $ 或 $ \Theta(n \log^2 n) $ 的做法;

继承暴力的思路,以 $ x $ 为数组下标,将所有纵坐标等于 $ x $ 的点分为一类,那么我们发现:

  1. 对于一个 $ size $ 较大的类个数不会太多,我们直接开一个桶暴力遍历维护一下即可;

  2. 对于 $ size $ 较小的类,其中包含的点数不会太多,所以我们直接处理出所有点对,然后 Hash一下,开一个 map 记一下即可;

所以根号分治,时间复杂度 $ \Theta(n \sqrt n) $,常数很大,要用cc-hash-table;

点击查看代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <map>
#include <algorithm>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
int n;
int sq;
vector<int> v[200005], a, b;
bool t[200005], vis[200005];
long long ans;
cc_hash_table<long long, long long> mp;
int main() {
	freopen("rect.in", "r", stdin);
	freopen("rect.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	sq = sqrt(n);
	int x, y;
	for (int i = 1; i <= n; i++) {
		cin >> x >> y;
		v[x].push_back(y);
	}
	for (int i = 1; i <= n; i++) {
		if (v[i].size() >= sq) a.push_back(i);
		else if (v[i].size()) b.push_back(i);
		sort(v[i].begin(), v[i].end());
	}
	for (int i = 0; i < a.size(); i++) {
		vis[a[i]] = true;
		for (int j = 0; j < v[a[i]].size(); j++) {
			t[v[a[i]][j]] = true;
		}
		for (int j = 1; j <= n; j++) {
			if (!v[j].size() || vis[j]) continue;
			long long sum = 0;
			for (int k = 0; k < v[j].size(); k++) {
				if (t[v[j][k]]) sum++;
			}
			ans += (sum * (sum - 1)) / 2;
		}
		for (int j = 0; j < v[a[i]].size(); j++) {
			t[v[a[i]][j]] = false;
		}
	}
	for (int i = 0; i < b.size(); i++) {
		for (int j = 0; j < v[b[i]].size(); j++) {
			for (int k = j + 1; k < v[b[i]].size(); k++) {
				long long now = v[b[i]][j] * 10000000000 + v[b[i]][k];
				ans += 1ll * mp[now];
				mp[now]++;
			}
		}
	}
	cout << ans;
	return 0;
}

标签:赛记,17,16,int,long,2005,Theta,include,id
From: https://www.cnblogs.com/PeppaEvenPig/p/18524519

相关文章

  • python-17-包和模块-创建属于自己的python工具包
    python-17-包和模块一.说明python中的基础系列关于组织代码的基本单位就是包和模块,在真实项目中我们不可能将所有代码都写在一起,或者我们的一些工具类库等需要单独处理,方便各模块调用,怎么办?这时候包和模块就来了,可以很方便的帮我们组织代码。来开始我们今天的日拱一卒!。......
  • Python轴承故障诊断 (17)基于TCN-CNN并行的一维故障信号识别模型
    往期精彩内容:Python-凯斯西储大学(CWRU)轴承数据解读与分类处理Pytorch-LSTM轴承故障一维信号分类(一)-CSDN博客Pytorch-CNN轴承故障一维信号分类(二)-CSDN博客Pytorch-Transformer轴承故障一维信号分类(三)-CSDN博客三十多个开源数据集|故障诊断再也不用担心数据集了!P......
  • Python轴承故障诊断 (16)高创新故障识别模型(二)
    往期精彩内容:Python-凯斯西储大学(CWRU)轴承数据解读与分类处理Pytorch-LSTM轴承故障一维信号分类(一)-CSDN博客Pytorch-CNN轴承故障一维信号分类(二)-CSDN博客Pytorch-Transformer轴承故障一维信号分类(三)-CSDN博客三十多个开源数据集|故障诊断再也不用担心数据集了!P......
  • 《python爬虫入门教程03--重剑无峰168》
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档python爬虫入门教程03前言一、urllib.request.urlretrieve()函数的介绍?二、使用示例总结前言本此程序主要演示python爬虫来简单爬取网页、图片、视频的示例。但是这是一个简单版的,一些未经过处理的网......
  • MU5IN160 – Parallel Programming
    SorbonneUniversité–SESIM2——–MU5IN160–ParallelProgrammingHands-onSession6–DataflowforMotionApplicationVeryimportant,aboutthesubmissionofyourworkAttheendofthissessionyouwillhavetouploadthefollowingfilesonMoodle:1......
  • 华为机试HJ16 购物单
    首先看一下题描述王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:主件附件电脑打印机,扫描仪书柜图书书桌台灯,文具工作椅无如果要买归类为附件的物品,必须先买该附件所属的主件,且每件物品只能购买一次。每个......
  • Adobe IC 下载与快捷键使用【2017-2024】
    目录一、AdobeIC功能介绍1.1强大的图像编辑能力1.2丰富的画笔与图层管理工具1.3模板库与高效协作二、AdobeIC下载与安装2.1下载2.2安装三、AdobeIC快捷键使用3.1基本编辑快捷键3.2视图与导航快捷键3.3协作与批注快捷键一、AdobeIC功能介绍1.1......