首页 > 其他分享 >2024.7.25 模拟赛总结

2024.7.25 模拟赛总结

时间:2024-07-29 15:40:13浏览次数:16  
标签:25 le 2024.7 int len times fa 区间 模拟

T1 ican

Statement:

给定一个有 \(n(1 \le n \le 10^7)\) 个元素的序列 \(a(a_i \le 10^9)\),求满足 \(i < j\) 且 \(a_i < a_j\) 的点对 \((i, j)\) 中 \(j - i\) 的最大值。

Solution:

考虑什么样的 \(a_i\) 可能作为点对中较靠左边的元素出现。显然对于一个 \(k > i\) 且 \(a_k \ge a_i\) 相较于 \(i\) 肯定是不优的,舍弃它不会影响答案。于是这些可能作为较左的点产生贡献的 \(a_i\) 组成了一个递减序列。同理可以得到一个可能作为较右的点对答案产生贡献的递增序列。由于序列的单调性,直接在上面做双指针即可。

T2 neverak

Statement:

给定一个由 \(a_1 \times a_2 \times a_3 \times .... \times a_n\) 个 \(n(n \le 10^5)\) 维 \(1 \times 1 \times 1 \times .... \times 1\) 的小立方体组成的 \(n\) 维立方体,现对其表面进行染色,问被染了 \(0, 1, 2 ... , 2n\) 个面的小立方体分别有多少个。

\(95\)% 数据满足 \(n \le 2000\).

Solution:

注意到每一维实际上是互不影响的,于是我们分别考虑每一维。第 \(i\) 维是被 \(1,a_i\) 夹住的,进而可以发现在这一维上有漏出的面的立方体,该维的坐标只有可能是 \(1\) 或 \(a_i\)。但是有可能 \(a_i = 1\),那么在这维上每一个立方体都会强制漏出 \(2\) 个面。于是我们考虑按维递推:设 \(f_{i, j}\) 是考虑前 \(i\) 个维,有 \(j\) 个面漏出来的小立方体数,转移如下:

  • \(a_i \ge 2: f_{i, j} = f_{i - 1, j} \times (a_i - 2) + f_{i - 1, j - 1} * 2\)

  • \(a_i = 1: f_{i, j} = f{i - 1, j - 2}\)

这样就得到一个 \(O(n^2)\) 算法,可以多项式优化到 \(O(n \log n)\) 但是我不会(待学)。

qwq
#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 4000 + 10, mod = 998244353;

int geta(int val){
	if(val < 0) return 0;
	val = val % mod; return val;
}

int n, a[N], cnt, f[N][N];

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n; f[0][0] = 1;
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1; i <= n; i++){
		for(int j = 0; j <= 2 * n; j++){
			if(a[i] >= 2) f[i][j] = ((f[i - 1][j - 1] * 2 % mod) + (f[i - 1][j] * geta(a[i] - 2)) % mod) % mod;
			else if(j >= 2) f[i][j] = f[i - 1][j - 2];
		}
	}
	for(int i = 0; i <= 2 * n; i++) cout << f[n][i] << " ";
		
	return 0;
}

T3 qtree

Statement:

略。

Solution:

容易想到两种暴力:

  • 每次查询时,把所有的标记点的距离记作 \(0\),跑一遍 \(\rm BFS\) 找到每个点的最短距离,并输出询问点的最短距离。

  • 每次查询时,把询问点和所有标记点的距离用 \(\rm LCA\) 求出来,取 \(\min\) 输出即可。

考虑把两种暴力综合起来,我们使用 大块更新,小块暴查 的思想,将这些询问分成 \(T\) 个块,每次处理完一个块就用 \(\rm BFS\) 更新答案,而在块中的修改就用第二种暴力求 \(\rm LCA\) 查询即可。两种操作分别的时间复杂度是 \(n\times S\) 和 \(n \log n \times \frac{q}{S}\),当 \(S = \sqrt{n \log n}\) 时两边取到等号。

当然还有点分树做法(待学)。

qwq
#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;

const int N = 1e5 + 10, INF = 1e9;

int n, q, dist[N], bksiz, b[N], _fa[N][18], dep[N]; 
struct edge{
	int v, next;
}edges[N << 1];
int head[N], idx;

inline void add_edge(int u, int v){
	edges[++idx] = {v, head[u]};
	head[u] = idx;
}

inline int min(int x, int y){
	if(x < y) return x;
	return y;
}

int Change[N], tot;

inline void change(){
	if(!tot) return; queue<int> Q;
	for(int i = 1; i <= tot; i++) dist[Change[i]] = 0, Q.push(Change[i]);
	while(!Q.empty()){
		int u = Q.front(); Q.pop();
		for(int i = head[u]; i; i = edges[i].next){
			int v = edges[i].v;
			if(dist[v] > dist[u] + 1) dist[v] = dist[u] + 1, Q.push(v);
		}
	}
	tot = 0;
}
inline void init(int u, int fa){
	dep[u] = dep[fa] + 1; _fa[u][0] = fa;
	for(int i = 1; (1 << i) < dep[u]; i++) _fa[u][i] = _fa[_fa[u][i - 1]][i - 1];
	for(int i = head[u]; i; i = edges[i].next){
		int v = edges[i].v; if(v == fa) continue;
		init(v, u);
	}
}
inline int LCA(int x, int y){
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = 17; i >= 0; i--) if(dep[_fa[x][i]] >= dep[y]) x = _fa[x][i];
	if(x == y) return x;
	for(int i = 17; i >= 0; i--) if(_fa[x][i] != _fa[y][i]) x = _fa[x][i], y = _fa[y][i];
	return _fa[y][0];
}

inline int query(int u){
	int ans = dist[u];
	for(int i = 1; i <= tot; i++) ans = min(ans, dep[u] + dep[Change[i]] - 2 * dep[LCA(u, Change[i])]);
//	cout << g[u] << " " << ans << "\n";
	return ans;
}

inline int read(){
	int ret = 0; char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') ret = (ret << 3) + (ret << 1) + (c - '0'), c = getchar();
	return ret;
}

inline void write(int x){
	if(!x) return;
	write(x / 10); putchar((char)((x % 10) + '0'));
}
inline void _write(int x){
	write(x); if(!x) putchar('0'); putchar('\n');
}

signed main(){
// 	freopen("10.in", "r", stdin);
// 	freopen("lsy.out", "w", stdout);
//	ios::sync_with_stdio(0);
//	cin.tie(0); cout.tie(0);
//	_write(1333); _write(0);
	n = read(); q = read(); bksiz = sqrt(n * log(n) / log(2));
	for(int i = 1; i <= n; i++) dist[i] = INF;
	for(int i = 1; i < n; i++){
		int x, y; x = read(); y = read();
		add_edge(x, y); add_edge(y, x);
	}
	init(1, 0); Change[++tot] = 1; b[1] = true; change();
	int cnt = 0;
	while(q--){
		int opt, x; opt = read(); x = read();
		if(cnt >= bksiz) change(), cnt = 0;
		if(opt == 1){
			if(!b[x]) Change[++tot] = x, b[x] = 1;
		}
		else{
			if(b[x]) _write(0);
			else{
				int val = query(x); _write(val);
			}
		}
		cnt++;
	}
	
	return 0;
}
/*
6 5
1 2
2 3
2 4
4 5
4 6
1 6
2 2
2 4
2 5
2 3
*/

T4 雨即实刑

Statement

给定 \(n(1 \le n \le 2000)\) 个开区间 \((l_i, r_i)\),初始时满足一定有一个 \(x\) 使得 \(\forall i (1 \le i \le n), l_i < x < r_i\)。每次你可以选择一个区间 \(i\),使它由 \((l_i, r_i)\) 变为 \((l_i + 1, r_i + 1)\) 或 \((l_i - 1, r_i - 1)\)。问最少需要多少次操作才可以使得区间两两无交。

Solution:

注意到原来的区间每个都有重叠的地方,尝试寻找突破口。手玩一下样例比较容易发现最后区间之间一定是紧密排列的,并且感性理解一下其中一定有一个区间是不动的。如果是这样的话,我们可以枚举这个区间左边有多少个区间,然后 \(\rm DP\) 计算。具体的,枚举固定的区间左边的区间数量 \(lsiz\)。设 \(f_{i, j, k}\) 为考虑前 \(i\) 个区间,左边填了 \(j\) 个数时,是(\(k = 1\))/否已经确定了不动的区间时的最少操作数。转移如下:

  • \(j > 0\)(填到左边):
    直接考虑 \(i\) 所需要的操作数是困难的,不妨考虑贡献法。若对于一个区间我们把它放在左边(从左到右)第 \(i\) 个区间,显然的他对于前面 \(i - 1\) 的区间的移动代价做出了 \(len_i\) 的贡献,接着考虑它自己移动的代价,显然它不考虑中间区间移动的代价是 \(l_i + len_i - l_{id}\)(其中 \(id\) 是固定区间的编号)。我们不知道 \(id\) 的具体值,但由于我们只考虑它本身产生的贡献,直接加上 \(l_i + len_i\) 即可。状态转移方程为 \(f_{i, j, k} = \min(f_{i, j, k}, f_{i - 1, j - 1, k} + i \times len_i + l_i)\)。

  • \(i > j\)(填到右边):同理可得\(f_{i, j, k} = \min(f_{i, j, k}, f_{i - 1, j, k} + (i - j - k) \times len_i + r_i)\)。

  • \(k = 1\)(作为不动区间):注意到在前面转移的时候对于左边的区间我们少考虑了 \(-l_{id}\) 的贡献,而对于右边的区间少考虑了 \(r_{id}\) 的贡献,加上即可。于是有 \(f_{i, j, k} = \min(f_{i, j, k}, f_{i - 1, j, k - 1})\)。

但是还有一个问题:不考虑中间填那个区间,什么样的摆放顺序才是最优的呢?注意到对于某一边不同的摆放顺序,一个区间 \(i\),\(l_i, r_i\) 对答案带来的贡献都是一样的,唯一不同的是 \(len_i\) 带来的贡献,注意到决策顺序带来的 \(len_i\) 前的系数从前往后都是不断变大的,于是我们贪心的让 \(len_i\) 较小的区间放到前面去。

于是我们得到了一个 \(O(n^3)\) 做法。考虑优化做法,我们再次发掘题目中的性质,并结合 贡献取到最小值时 \(lsiz\) 的值可以观察出:最优情况下,固定的区间左右区间数量差小于等于 \(1\)。这个直觉是我们可以将区间整体向少的一边偏移而得到更小的答案。于是我们只需要计算至多 \(2\) 个 \(lsiz\) 便可以得到答案。时间复杂度来到了 \(O(n^2)\)。

qwq
#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 5000 + 10, INF = 1e18;

int n, f[N][N][2], ans = INF;
struct line{
	int l, r, len;
}L[N];
bool cmp(struct line l1, struct line l2){return l1.len > l2.len;}

void solve(int lsiz){
	for(int i = 0; i <= n; i++)
		for(int j = 0; j <= n; j++)
			for(int k = 0; k <= 1; k++)
				f[i][j][k] = INF;
	f[0][0][0] = 0; int rsiz = n - 1 - lsiz;
	for(int i = 1; i <= n; i++){
		for(int j = 0; j <= min(i, lsiz); j++){
			for(int k = 0; k + j <= i && k <= 1; k++){
				int lcnt = j, rcnt = i - lcnt - k;
				if(lcnt) f[i][j][k] = f[i - 1][j - 1][k] + lcnt * L[i].len + L[i].l; 
				if(rcnt) f[i][j][k] = min(f[i][j][k], f[i - 1][j][k] + rcnt * L[i].len - L[i].r);
				if(k) f[i][j][k] = min(f[i][j][k], f[i - 1][j][k - 1] - lsiz * L[i].l + rsiz * L[i].r);
			}
		}
	}
	ans = min(ans, f[n][lsiz][1]);
}

signed main(){
	//freopen("5.in", "r", stdin);
	//freopen("lsy.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n; for(int i = 1; i <= n; i++) cin >> L[i].l >> L[i].r, L[i].len = L[i].r - L[i].l ;
	sort(L + 1, L + n + 1, cmp);
	solve(n / 2); if(n % 2 == 0) solve(n / 2 - 1);
	cout << ans << "\n";

	return 0;
}

标签:25,le,2024.7,int,len,times,fa,区间,模拟
From: https://www.cnblogs.com/little-corn/p/18324528

相关文章

  • 912、基于51单片机的温度控制(PID,模拟控制,除雾器)
    完整资料或代做滴滴我(有偿)目录一、设计功能二、proteus仿真三、原理图四、程序源码五、资料包括一、设计功能设计中镜片除雾器,当温度过低时启动镜片上的加热膜进行加热,从而实现对镜片上温度的控制,实现只能除雾;保持镜片温度为25度。二、proteus仿真三......
  • 模拟冲刺sprint
    用户故事1:赛事与赛程管理用户故事描述:我们渴望拥有一个智能、高效的赛事管理系统,它能够极大地简化赛事组织流程,减轻我们的工作负担,同时提升赛事的专业性和观众体验。用户能够设置和编辑多校联赛的赛事及赛程信息。任务拆分:任务1.1:设计赛事信息数据库模型(名称、时间、地......
  • 【2024-07-25】连岳摘抄
    23:59我们从来不搞一鸣惊人的事情,我们什么事情都慢慢来,实际上很快。                                                 ——XXX人的记忆,倾向于记住不愉快的事,而忽视愉......
  • 海贼王25
           ......
  • 【FMC155】基于VITA57.1标准的2路500MSPS/1GSPS/1.25GSPS 14位直流耦合AD采集FMC子卡
     板卡概述       FMC155是一款基于VITA57.1标准的,实现2路14-bit、500MSPS/1GSPS/1.25GSPS直流耦合ADC同步采集FMC子卡模块。该模块遵循VITA57.1规范,可直接与FPGA载卡配合使用,板卡ADC器件采用ADI的AD9680芯片,该芯片具有两个模拟输入通道和两个JESD204B输出数据通道对,可......
  • 2024.7.26
    1.string函数族改写,用指针修改。strlenstrcatstrcpystrcmp......
  • 模拟噪声常见误区
    简介    噪声是模拟电路设计的一个核心问题,它会直接影响能从测量中提取的信息量,以及能获取所需信息的经济成本。遗憾的是,关于噪声有许多混淆和误导的信息,可能导致性能不佳、高成本的过渡设计或资源使用效率低下。1降低电路中的电阻值总是能改善噪声性能    ......
  • 昇思25天学习打卡营第16天|GAN 图像生成指南:数据集和模型训练手册
    目录MindSpore环境配置、MNIST数据集下载及处理展开。数据集可视化隐码构造模型构建模型训练效果展示模型推理MindSpore环境配置、MNIST数据集下载及处理展开。        首先,通过命令行操作安装特定版本的MindSpore库,并查看其版本。接着,从指定URL......
  • 昇思25天学习打卡营第24天|生成式-Diffusion扩散模型
    打卡目录打卡理解扩散模型环境设置DiffusionModel简介扩散模型实现原理Diffusion前向过程Diffusion逆向过程训练算法总结U-Net神经网络预测噪声构建Diffusion模型准备函数和类位置向量ResNet/ConvNeXT块Attention模块组归一化条件U-Net正向扩散(core)......
  • CVE-2015-5254
    目录漏洞描述漏洞利用流程如下复现过程漏洞利用思路总结漏洞描述ApacheActiveMQ是由美国Pachitea(Apache)软件基金会开发的开源消息中间件,支持Java消息服务、集群、Spring框架等。影响版本:ApacheActiveMQ5.13.0之前5.x版本,该程序导致的漏洞并不限制可以在......