首页 > 其他分享 >NOIP 模拟赛 #20 - D 题解

NOIP 模拟赛 #20 - D 题解

时间:2024-11-28 20:11:25浏览次数:5  
标签:20 NOIP 题解 ll maxn vec yti fi xti

D

一个 \(n\times m\) 的网格图,一开始所有格子颜色都是 \(0\)。有 \(k\) 次染色操作,每次把第 \(l\sim r\) 行或第 \(l\sim r\) 列中的格子全都染成颜色 \(c\)。在所有染色操作完成后,设 $c_{i, j} 为格子 \((i, j)\) 的颜色,求 \(\sum\limits_{i = 1} ^ n \sum\limits_{j = 1} ^ m ([i < n \land c_{i, j} = c_{i + 1, j}] + [j < m \land c_{i, j} = c_{i, j + 1}])\) 以及 \(\sum\limits_{i = 1} ^ {n - 1} \sum\limits_{j = 1} ^ m ([j < m \land c_{i, j} = c_{i + 1, j + 1}] + [j > 1 \land c_{i, j} = c_{i + 1, j - 1}])\)。

\(1\le n, m, k\le 10^5\)

对于每一行求出其最晚染色时间 \(xt_i\) 以及染的颜色 \(x_i\),同理求出 \(yt_i\) 和 \(y_i\),那么格子 \((i, j)\) 的颜色只可能出自 \(x_i, y_j\)。

考虑第一个答案,行和列分别做一次。考虑每一行的答案,我们把该行格子分为 A(\(xt_i \ge yt_j\) 的格子)类和 B(\(xt_i > yt_j\))类,我们需要统计 AA 的数量,AB 和 BB 的贡献。

按时间顺序依次加入,加入一列时更新一下 AB 和 BB 的贡献,可以使用桶,并实时更新 AA 的数量。

考虑第二个答案,我们分为 AA , BB , AB 三种贡献。

对于 AA,枚举列 \(j\),由于两个格子 \((i, j), (i + 1, j + 1)\) 都不能被列染色,所以 \(xt_i \ge yt_j, \ xt_{i + 1} \ge yt_{j + 1}\),可以二维数点。

对于 BB,枚举列 \(j\),若 \(y_j = y_{j + 1}\) 则可能有贡献,对 \(xt_i < yt_j, \ xt_{i + 1} < yt_{j + 1}\) 做二维数点。

对于 AB,需要匹配对应的颜色,容易想到对每种颜色分别做一遍,同样是二维数点。

时间复杂度 \(\mathcal O((n + m) \log k)\)。

点击查看代码
#include <bits/stdc++.h>
namespace Initial {
	#define ll long long
	#define ull unsigned long long
	#define fi first
	#define se second
	#define mkp make_pair
	#define pir pair <ll, ll>
	#define pb emplace_back
	#define i128 __int128
	using namespace std;
	template <class T>
	void rd(T &x) {
		char ch;
		while(!isdigit(ch = getchar())) ;
		x = ch - '0';
		while(isdigit(ch = getchar()))
			x = (x << 1) + (x << 3) + ch - '0';
	}
	void write(const ll x, const char str[] = "") {
		if(x > 9) write(x / 10);
		putchar(x % 10 + '0'), printf("%s", str);
	}
	const ll maxn = 1e5 + 10, inf = 1e18, mod = 1e9 + 7;
	ll power(ll a, ll b = mod - 2) {
		ll s = 1;
		while(b) {
			if(b & 1) s = 1ll * s * a %mod;
			a = 1ll * a * a %mod, b >>= 1;
		} return s;
	}
	template <class T>
	const ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }
	template <class T>
	void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }
	template <class T>
	void chkmax(T &x, const T y) { x = x < y? y : x; }
	template <class T>
	void chkmin(T &x, const T y) { x = x > y? y : x; }
} using namespace Initial;

ll n, m, k, tp, x[maxn], xti[maxn], y[maxn], yti[maxn], ans;
vector <ll> t_x[maxn], t_y[maxn];

namespace Get_Time {
	vector <pir> vec_x[maxn], vec_y[maxn];
	ll vis[maxn];
	void solve() {
		rd(n), rd(m), rd(k), rd(tp);
		for(ll i = 1; i <= k; i++) {
			ll op, l, r, c; rd(op), rd(l), rd(r), rd(c);
			if(op == 0) vec_x[l].pb(mkp(i, c)), vec_x[r + 1].pb(mkp(-i, c));
			else vec_y[l].pb(mkp(i, c)), vec_y[r + 1].pb(mkp(-i, c));
		} priority_queue <pir> q;
		for(ll i = 1; i <= n; i++) {
			for(pir t: vec_x[i])
				if(t.fi > 0) q.push(t), vis[t.fi] = 1;
				else vis[-t.fi] = 0;
			while(!q.empty() && vis[q.top().fi] == 0) q.pop();
			if(!q.empty()) x[i] = q.top().se, xti[i] = k - q.top().fi;
			else xti[i] = k;
			t_x[xti[i]].pb(i);
		} while(!q.empty()) q.pop();
		for(ll i = 1; i <= m; i++) {
			for(pir t: vec_y[i])
				if(t.fi > 0) q.push(t), vis[t.fi] = 1;
				else vis[-t.fi] = 0;
			while(!q.empty() && vis[q.top().fi] == 0) q.pop();
			if(!q.empty()) y[i] = q.top().se, yti[i] = k - q.top().fi;
			else yti[i] = k;
			t_y[yti[i]].pb(i);
		}
	}
}

namespace FFB {
	ll cnt[maxn], kk, sp, bin[maxn];
	vector <ll> vec_x[maxn], vec_y[maxn];
	void solve() {
		memset(cnt, 0, sizeof cnt), kk = 0, sp = m - 1;
		memset(bin, 0, sizeof bin);
		for(ll i = 0; i <= k; i++) {
			for(ll j: t_y[i]) {
				bin[j] = 1;
				if(j < m && !bin[j + 1]) ++cnt[y[j]], --sp;
				if(j > 1 && !bin[j - 1]) ++cnt[y[j]], --sp;
				if(j < m && bin[j + 1]) --cnt[y[j + 1]];
				if(j > 1 && bin[j - 1]) --cnt[y[j - 1]];
				kk += (bin[j + 1] && y[j + 1] == y[j])
				 + (bin[j - 1] && y[j - 1] == y[j]);
			}
			for(ll j: t_x[i])
				ans += cnt[x[j]] + kk + sp;
		}
	}
}

ll tree[maxn], used[maxn];
void add(ll x, ll v) {
	for(; x <= k + 1; x += x & -x) tree[x] += v;
}
ll ask(ll x) {
	ll v = 0;
	for(; x; x -= x & -x) v += tree[x];
	return v;
}

namespace AA_BB {
	vector <pir> vec, _vec;
	void solve() {
		vec.clear(), _vec.clear();
		for(ll i = 1; i <= m; i++) {
			if(i < m && y[i] == y[i + 1]) vec.pb(mkp(yti[i], yti[i + 1]));
			if(i > 1 && y[i] == y[i - 1]) vec.pb(mkp(yti[i], yti[i - 1]));
		}
		for(ll i = 1; i < n; i++)
			_vec.pb(mkp(xti[i], xti[i + 1]));
		sort(vec.begin(), vec.end()), sort(_vec.begin(), _vec.end());
		for(ll i = 0, j = 0; i < _vec.size(); i++) {
			while(j < vec.size() && vec[j].fi <= _vec[i].fi)
				add(vec[j++].se + 1, 1);
			ans += ask(_vec[i].se + 1);
		}
		
		vec.clear(), _vec.clear();
		for(ll i = 1; i <= m; i++) {
			if(i < m) vec.pb(mkp(yti[i] - 1, yti[i + 1] - 1));
			if(i > 1) vec.pb(mkp(yti[i] - 1, yti[i - 1] - 1));
		} memset(tree, 0, sizeof tree);
		for(ll i = 1; i < n; i++)
			if(x[i] == x[i + 1]) _vec.pb(mkp(xti[i], xti[i + 1]));
		sort(vec.begin(), vec.end(), greater <pir> ());
		sort(_vec.begin(), _vec.end(), greater <pir> ());
		for(ll i = 0, j = 0; i < _vec.size(); i++) {
			while(j < vec.size() && _vec[i].fi <= vec[j].fi)
				add(k + 1 - vec[j++].se, 1);
			ans += ask(k + 1 - _vec[i].se);
		}
	}
}

namespace AB {
	vector <pir> vec[maxn], _vec[maxn]; 
	void solve() {
		memset(tree, 0, sizeof tree);
		for(ll i = 0; i <= k; i++) vec[i].clear(), _vec[i].clear();
		for(ll i = 1; i <= m; i++) {
			if(i < m) vec[y[i]].pb(mkp(yti[i], yti[i + 1] - 1));
			if(i > 1) vec[y[i]].pb(mkp(yti[i], yti[i - 1] - 1));
		}
		for(ll i = 1; i <= n; i++) {
			if(i < n) _vec[x[i]].pb(mkp(xti[i + 1], xti[i]));
			if(i > 1) _vec[x[i]].pb(mkp(xti[i - 1], xti[i]));
		}
		for(ll c = 0; c <= k; c++) { 
			if(vec[c].empty() || _vec[c].empty()) continue;
			sort(vec[c].begin(), vec[c].end());
			sort(_vec[c].begin(), _vec[c].end());
			for(ll i = 0, j = 0; i < _vec[c].size(); i++) {
				ll lim = _vec[c][i].fi;
				while(j < vec[c].size() && vec[c][j].fi <= lim)
					add(k + 1 - vec[c][j++].se, 1);
				ans += ask(k + 1 - _vec[c][i].se);
				if(i + 1 == _vec[c].size())
					while(j--) add(k + 1 - vec[c][j].se, -1);
			}
		}
	}
}

int main() {
	freopen("painting.in", "r", stdin);
	freopen("painting.out", "wb", stdout);
	Get_Time::solve();
	FFB::solve();
	if(tp) AB::solve(), AA_BB::solve();
	swap(n, m), swap(x, y), swap(xti, yti);
	swap(t_x, t_y), FFB::solve();
	write(ans, "\n");
	return 0;
}

标签:20,NOIP,题解,ll,maxn,vec,yti,fi,xti
From: https://www.cnblogs.com/Sktn0089/p/18575080

相关文章

  • 多校A层冲刺NOIP2024模拟赛27终结篇
    多校A层冲刺NOIP2024模拟赛27终结篇前言就一定要让我挂分吗???T1证出结论后却交了一发错解,成功挂100。T2是不是可以直接贪,直接写。T2写完了,tm怎么也没有大样例?T3是不是可以线段树。T3是不是不可以线段树。T4是不是可以K-DTree,但我不会写K-DTree。T4是不是可以......
  • NOIP2024 前集训:多校A层冲刺NOIP2024模拟赛 27 终结篇
    前言点击查看代码《蜂鸟》传说中人类在远早住于黑暗的地下之遥派出了娇小的蜂鸟找到通往光明的隧道飞过了一座一座岛好想有一个地方落脚把一个一个梦制造会不会有人能够听到寻找太阳的梦自不量力说自己也变成太阳的念头有时候寂寞几乎扛不动咽在喉咙......
  • 2024-0xGame-WEB方向全题解
    0xGameRound1ez_rce源码:fromflaskimportFlask,requestimportsubprocessapp=Flask(__name__)@app.route("/")defindex():returnopen(__file__).read()@app.route("/calc",methods=['POST'])defcalculator():ex......
  • 2024.11.[~, 28]训练记录
    好,今天是noip2024前最后一次模拟。但是我参加不了noip。还是认真参加了模拟赛。自主复习就写训练记录吧。落下很多天了。今天的题疑似有点难订正了。那就先写今天的。11.28noip模拟今天的考试时间为了全真对标特意推迟了半个小时,写到最后还是有点困了。毕竟平常一点钟睡午......
  • 多校A层冲刺NOIP2024模拟赛27终结篇
    多校A层冲刺NOIP2024模拟赛27终结篇\(T1\)A.【模板】分治FFT\(0pts\)将式子展开后是一个形如\(f_{n}\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{i-1}a_{i,j}\)的形式。考虑\(f_{n}\)如何转移。当我们选出一对\((i,j)\)进行合并进入\(n'=n-1\)的子问题,故\(a_{i}......
  • 摩尔线程 国产显卡 MUSA 并行编程 学习笔记-2024/11/28
    LearningRoadmap:Section1:IntrotoParallelProgramming&MUSADeepLearningEcosystem(摩尔线程国产显卡MUSA并行编程学习笔记-2024/11/20)Ubuntu+Driver+Toolkit+conda+pytorch+torch_musa环境安装(摩尔线程国产显卡MUSA并行编程学习笔记-2024/11/24-CSDN博客)C/C++R......
  • 2024.11.28
    DPP1048[NOIP2005普及组]采药-洛谷|计算机科学教育新生态#include<iostream>usingnamespacestd;intt[101],w[101];intdp[1001];intmain(){intT,M;cin>>T>>M;for(inti=1;i<=M;i++){cin>>t[i]>>w[i];}......
  • 7-20 表达式转换 预习报告
    1、问题定义表达式转换2、问题分析这道题目显然用到了栈这一数据结构,栈的特点是元素的先进后出,与题目的要求中的将中缀表示法转换为后缀表示法有相似的地方。任务中要求将输入的中缀表达式转换为后缀表达式,即为给定一个用中缀表示法表示的算术表达式,转换为用后缀表示法表......
  • 2024.11.20训练记录
    pack设当前手上的钱数为x。二分一段一段跳的复杂度是对的。因为,如果下一段的代价总和sum<\dfrac{x}{2}。那么这一段的下一个数肯定也小于\dfrac{x}{2}。因为是从大到小排。所以还能继续选下一个数,引出矛盾。所以每段的代价总和只能大于\dfrac{x}{2}。那段数就是log级别的。......
  • 力控组态实现延时5s延时触发,命令间隔200ms
    最近做一个阀门开度随液位变化的程序,液位设定一个目标值,液位高于目标值,阀门开度减小;液位低于目标值,阀门开度增加。很明显,该程序适合用PID控制,在大循环中计算阀门开度值,并下置给阀门,结果,设备经常离线原因:经分析,大循环中运行,数据下置太快,设备反应不过来,导致通讯超时,或者是撞......