2025-12-25~26 hetao1733837的刷题记录

2025-12-25~26 hetao1733837的刷题记录

12-25

LG9447 [ICPC 2021 WF] Spider Walk

原题链接:[ICPC 2021 WF] Spider Walk

分析

今天我一定要在洛谷上过一道紫!感觉是 + ∞ +\infty +∞ 天前 a o a o aoao aoao 推给我的,记得当时他还是半停课,我还是蒟蒻;现在他去冲省队了,我还是蒟蒻/ll

可能不是好题,算普通题,但是,很有意思。

我们设 d i , j d_{i,j} di,j 表示环上 i i i 到 j j j 的距离, f i f_i fi 表示从 s s s 到达 i i i 的最少搭桥数,显然起点设在 s s s 的无限远位置比较合适。经过我感性理解, ∣ f i − f j ∣ ≤ d i , j |f_{i}-f_{j}|\le d_{i,j} ∣fi−fj∣≤di,j。

初始 f i = d i , s f_i=d_{i,s} fi=di,s,从外向内加蛛丝,加蛛丝的两条射线会影响周围的一些射线之间的距离,则变成了区间减和区间最小值,上线段树即可。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 200005, M = 500005, inf = 0x3f3f3f3f;
int n, m, S; 
pair<int, int> a[M];
struct segtree{
	int tag1[N << 2], tag2[N << 2];
	void down(int p, int l, int r){
		int mid = (l + r) >> 1;
		if (tag1[p] != inf){
			tag1[p << 1] = min(tag1[p << 1], tag1[p]);
			tag1[p << 1 | 1] = min(tag1[p << 1 | 1], tag1[p] + mid - l + 1);
			tag1[p] = inf;
		}
		if (tag2[p] != inf){
			tag2[p << 1] = min(tag2[p << 1], tag2[p]);
			tag2[p << 1 | 1] = min(tag2[p << 1 | 1], tag2[p] - mid + l - 1);
			tag2[p] = inf;
		}
	}
	void build(int p, int l, int r){
		tag1[p] = tag2[p] = inf;
		if (l == r){
			if (l == S){
				tag1[p] = tag2[p] = 0;
			} 
			else{
				tag1[p] = tag2[p] = inf;
			}
			return ;
		}
		int mid = (l + r) >> 1;
		build(p << 1, l, mid); 
		build(p << 1 | 1, mid + 1, r);
	}
	void upd1(int p, int l, int r, int s, int t, int &v){
		if (l > t || r < s) 
            return;
		if (s <= l && r <= t){
            tag1[p] = min(tag1[p], v);
            v += (r - l + 1);
            return ;
        }
		int mid = (l + r) >> 1; 
        down(p, l, r);
        if (s <= mid)
    		upd1(p << 1, l, mid, s, t, v); 
        if (t > mid)
            upd1(p << 1 | 1, mid + 1, r, s, t, v);
	}
	void upd2(int p, int l, int r, int s, int t, int &v){
		if (l > t || r < s) 
            return;
		if (s <= l && r <= t){
            tag2[p] = min(tag2[p], v);
            v -= (r - l + 1);
            return ;
        }
		int mid = (l + r) >> 1; 
        down(p, l, r);
        if (s <= mid)
    		upd2(p << 1, l, mid, s, t, v); 
        if (t > mid)
            upd2(p << 1 | 1, mid + 1, r, s, t, v);
	}
	void update1(int p, int l, int r, int s, int v){
		if (l == r){
            tag1[p] = min(tag1[p], v);
            tag2[p] = min(tag2[p], v);
            return ;
        }
		int mid = (l + r) >> 1; 
        down(p, l, r);
		if (s <= mid)
            update1(p << 1, l, mid, s, v);
        else
            update1(p << 1 | 1, mid + 1, r, s, v);
	}
	void update2(int p, int l, int r, int s, int v) {
		if (l == r){
            tag1[p] = tag2[p] = v;
            return ;
        }
		int mid = (l + r) >> 1; 
        down(p, l, r);
        if (s <= mid)
            update2(p << 1, l, mid, s, v);
        else
            update2(p << 1 | 1, mid + 1, r, s, v);
	}
    int query(int p, int l, int r, int s){
		if (l == r) 
			return min(tag1[p], tag2[p]);
		int mid = (l + r) >> 1; 
		down(p, l, r);
		if (s <= mid)
			return query(p << 1, l, mid, s);
		else
			return query(p << 1 | 1, mid + 1, r, s);
	}
    void write(int p, int l, int r) {
		if (l == r){
            cout << min(tag1[p], tag2[p]) << '\n';
            return ;
        }
		int mid = (l + r) >> 1; 
        down(p, l, r);
		write(p << 1, l, mid); 
        write(p << 1 | 1, mid + 1, r);
	}
}T;
void change(int x){
	T.update1(1, 1, n, x, min(T.query(1, 1, n, x % n + 1), T.query(1, 1, n, x > 1 ? x - 1 : n)) + 1);
}
void spread(int x) {
	int g, f = T.query(1, 1, n, x);
	T.upd1(1, 1, n, 1, x - 1, g = f + n - x + 1); 
    T.upd1(1, 1, n, x + 1, n, g = f + 1);
	T.upd2(1, 1, n, 1, x - 1, g = f + x - 1); 
    T.upd2(1, 1, n, x + 1, n, g = f + n - 1);
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m >> S;
	for (int i = 1; i <= m; i++){
		cin >> a[i].first >> a[i].second;
	}
	sort(a + 1, a + m + 1, greater<pair<int, int> >());
	T.build(1, 1, n); spread(S);
	for (int i = 1; i <= m; i++){
		int x = a[i].second;
		int y = x % n + 1;
		int fx = T.query(1, 1, n, x), fy = T.query(1, 1, n, y);
		T.update2(1, 1, n, y, fx); 
		T.update2(1, 1, n, x, fy);
		change(x); 
		change(y); 
		spread(x); 
		spread(y);
	} 
	T.write(1, 1, n);
}

这电脑抽什么风?我的刷题笔记和昨天自组模拟赛的总结全没了/ll

CF1748E Yet Another Array Counting Problem

原题链接1:E. Yet Another Array Counting Problem

原题链接2:CF1748E Yet Another Array Counting Problem

啊,我的思路!我的正解!全没了!

正确思路

追忆 一下啊......

哦,有个关键性质就是说这个所谓的"最左端最大值位置"是支持合并的......呃,好像一句话概括完了。

那么,枚举断点,设 d p k , j dp_{k,j} dpk,j 表示 b k ≤ j b_k\le j bk≤j 时,区间 [ L , R ] [L,R] [L,R]的方案数。

转移则显然
d p k , j = d p k , j − 1 + d p k [ L ] , j − 1 × d p k [ R ] , j dp_{k,j}=dp_{k,j-1}+dp_{k[L], j-1}\times dp_{k[R],j} dpk,j=dpk,j−1+dpk[L],j−1×dpk[R],j

我觉得是这样吧......欸,我好像给花花有截屏!

总感觉少点什么呢......

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
#define mod 1000000007
using namespace std;
const int N = 200005;
int t;
int n, m, a[N];
vector<int> dp[N];
struct segtree{
	int pos[N << 2];
	void pushup(int p){
		if (a[pos[p << 1]] < a[pos[p << 1 | 1]])
			pos[p] = pos[p << 1 | 1];
		else
			pos[p] = pos[p << 1];	
	}
	void build(int p, int l, int r){
		if (l == r){
			pos[p] = l;
			return ;
		}
		int mid = (l + r) >> 1;
		build(p << 1, l, mid);
		build(p << 1 | 1, mid + 1, r);
		pushup(p);
	}
	int query(int p, int l, int r, int s, int t){
		if (s <= l && r <= t){
			return pos[p];
		}		
		int mid = (l + r) >> 1;
		if (s > mid)
			return query(p << 1 | 1, mid + 1, r, s, t);
		else if (t <= mid)
			return query(p << 1, l, mid, s, t);
		int res1 = query(p << 1, l, mid, s, t);
		int res2 = query(p << 1 | 1, mid + 1, r, s, t);
		if (a[res1] < a[res2])
			return res2;
		else
			return res1;
	}
}T;
int dfs(int l, int r){
	if (l > r)
		return -1;
	if (l == r){
		for (int j = 1; j <= m; j++)
			dp[l][j] = j;
		return l;
	}	
	int pos = T.query(1, 1, n, l, r);
	int L = dfs(l, pos - 1);
	int R = dfs(pos + 1, r);
	if (L == -1){
		for (int j = 1; j <= m; j++){
			dp[pos][j] = (dp[R][j] + dp[pos][j - 1]) % mod;
		}
	}
	else if (R == -1){
		for (int j = 1; j <= m; j++){
			dp[pos][j] = (dp[L][j - 1] + dp[pos][j - 1]) % mod;
		}
	}
	else{
		for (int j = 1; j <= m; j++){
			dp[pos][j] = (dp[pos][j - 1] + dp[L][j - 1] * dp[R][j]) % mod;
		}
	}
	return pos;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> t;
	while (t--){
		cin >> n >> m;
		for (int i = 1; i <= n; i++){
			cin >> a[i];
			dp[i].clear();
			dp[i].resize(m + 5);
		}
		T.build(1, 1, n);
		int k = dfs(1, n);
		cout << dp[k][m] << '\n';
	}
}

LG6829 [IOI 2020] 植物比较

原题链接:[IOI 2020] 植物比较

其实,个人觉得去LOJ交更能模拟那个不同的头文件。

正确思路

这个是个超强构造!构造原理就是对于一个位置,其前 k − 1 k-1 k−1 给位置都已经选了或都是 0 0 0,然后这个位置是 0 0 0,将其赋值为当前序列最大值。

这样就可以构造出来了,线段树+set 优化到 O ( n l o g n ) O(nlogn) O(nlogn)。

然后,对于 2 × k > n 2\times k > n 2×k>n 的,显然有唯一构造,获得很多部分分!

然后对每个位置记录 p r e pre pre 和 n x t nxt nxt 表示向左/右跳 k k k 个位置比他小的数的最大的位置,套一个倍增。

对于询问 ( x , y ) (x,y) (x,y),假定 h x > h y h_x>h_y hx>hy,然后从 x x x 出发开始跳,如果跳到 y y y 的过程中每一个位置都 > h y >h_y >hy,那就可行了。

反之,则假定 h y > h x h_y>h_x hy>hx,同理。

若都无法得到答案,输出 0 即可。

正解

cpp 复制代码
#include <bits/stdc++.h>
// #include "plants.h"
#define LL long long
using namespace std; 
const int N = 200005;
const int inf = 0x7f7f7f7f;
int n, k, R[N];
struct segtree2{
	int cur[N], node[N], mx[N << 2];
	int maxn(int x, int y){
		if (cur[x] > cur[y])
			return x;
		else	
			return y;
	}
	void pushup(int p){
		mx[p] = maxn(mx[p << 1], mx[p << 1 | 1]);
	}
	void build(int p, int l, int r){
		if (l == r){
			node[l] = p;
			mx[p] = l;
			return ;
		}
		int mid = (l + r) >> 1;
		build(p << 1, l, mid);
		build(p << 1 | 1, mid + 1, r);
		pushup(p);
	}
	void init1(){
		memset(cur, 0, (n + 1) << 2);
		build(1, 1, n);
	}
	void modify(int p, int v){
		if (p < 1 || p > n){
			return ;
		}
		static int tmp; 
		mx[node[p]] = p; 
		tmp = node[p] >> 1;
		cur[p] = v; 
		while (tmp){
			pushup(tmp);
			tmp >>= 1;
		} 
	}
	int got(){
		static int res;
		res = mx[1];
		if (cur[res] >= k){
			modify(res, 0);
			return res;
		}
		else{
			return 0;
		}
	}
	int ll, rr, ans;
	void init2(){
		memset(cur, 0, (n + 1) << 2);
		memset(mx, 0, (n * 4 + 1) << 2);
		cur[0] = -1;
	}
	void query1(int p, int l, int r){
		if (ll <= l && r <= rr){
			ans = maxn(ans, mx[p]);
			return ;
		}
		int mid = (l + r) >> 1;
		if (ll <= mid){
			query1(p << 1, l, mid);
		}
		if (rr > mid){
			query1(p << 1 | 1, mid + 1, r);
		}
	}
	int query2(int l, int r){
		ans = 0;
		ll = max(1, l);
		rr = min(n, r);
		if (ll <= rr)
			query1(1, 1, n);
		return ans;
	}
}T2;
set<int> S;
bool buc[N];
typedef set<int>::iterator IT;
void recalc(int x){
	static IT it;
	if (buc[x]){
		it = S.find(x);
		if (it == S.begin()){
			it = S.end();
			it--;
			if (*it == x){
				T2.modify(x, n);
			}
			else{
				T2.modify(x, x + n - *it);
			}
		}
		else{
			--it;
			T2.modify(x, x - *it);
		}
	}
	else{
		T2.modify(x, 0);
	}
}
void Ins(int x){
	static IT it;
	buc[x] = 1;
	it = S.insert(x).first;
	it++;
	if (it == S.end())
		it = S.begin();
	recalc(x);
	recalc(*it);
}
void Del(int x){
	static IT it;
	static int v;
	buc[x] = 0;
	it = S.find(x);
	it++;
	if (it == S.end()){
		it = S.begin();
	}
	v = *it;
	S.erase(S.find(x));
	recalc(v);
	recalc(x);
}
struct segtree1{
	int tag[N << 2], mn[N << 2];
	void pushup(int p){
		mn[p] = min(mn[p << 1], mn[p << 1 | 1]);
	}
	void maketag(int p, int v){
		tag[p] += v;
		mn[p] += v;
	}
	void down(int p){
		if (tag[p]){
			maketag(p << 1, tag[p]);
			maketag(p << 1 | 1, tag[p]);
			tag[p] = 0;
		}
	}
	void build(int p, int l, int r){
		if (l == r){
			mn[p] = R[l];
			return ;
		}
		int mid = (l + r) >> 1;
		build(p << 1, l, mid);
		build(p << 1 | 1, mid + 1, r);
		pushup(p);
	}
	int ll, rr;
	void update(int p, int l, int r){
		if (ll <= l && r <= rr){
			maketag(p, -1);
			return ;
		}
		down(p);
		int mid = (l + r) >> 1;
		if (ll <= mid)
			update(p << 1, l, mid);
		if (rr > mid)
			update(p << 1 | 1, mid + 1, r);
		pushup(p);
	}
	void Work(int p, int l, int r){
		if (mn[p] > 0)
			return ;
		if (l == r){
			mn[p] = inf;
			Ins(l);
			return ;
		}
		down(p);
		int mid = (l + r) >> 1;
		Work(p << 1, l, mid);
		Work(p << 1 | 1, mid + 1, r);
		pushup(p);
	}
	void init(){
		build(1, 1, n);
	}
	void work(){
		Work(1, 1, n);
	}
	void upd(int l, int r){
		ll = l;
		rr = r;
		if (ll <= rr){
			update(1, 1, n);
		}
	}
}T1;
int a[N], b[N], la[N][20], ne[N][20], ld[N][20], nd[N][20], L;
void Main(){
	T2.init1();
	T1.init();
	T1.work();
	int i, j, x, p, now = n;
	while (now){
		x = T2.got();
		a[x] = now;
		now--;
		Del(x);
		if (x >= k){
			T1.upd(x - k + 1, x);
		}
		else{
			T1.upd(1, x);
			T1.upd(n - (k - x) + 1, n);
		}
		T1.work();
	}
	for (i = 1; i <= n; ++i){
		b[a[i]] = i;
	}
	T2.init2();
	for (i = 1; i <= n; ++i){
		p = b[i];
		la[p][0] = T2.query2(p - k + 1, p - 1);
		if (la[p][0]){
			ld[p][0] = p - la[p][0];
		}
		ne[p][0] = T2.query2(p + 1, p + k - 1);
		if (ne[p][0]){
			nd[p][0] = ne[p][0] - p;
		}
		if (p - k + 1 < 1){
			x = T2.query2(p - k + 1 + n, n);
			if (a[x] > a[la[p][0]]){
				la[p][0] = x;
				ld[p][0] = p + n - x;
			}
		}
		if (p + k - 1 > n){
			x = T2.query2(1, p + k - 1 - n);
			if (a[x] > a[ne[p][0]]){
				ne[p][0] = x;
				nd[p][0] = x + n - p;
			}
		}
		T2.modify(p, i);
	}
	L = 1;
	while ((1 << L) < n)
		L++;
	for (j = 1; j <= L; j++){
		for (i = 1; i <= n; i++){
			if ((p = la[i][j - 1])){
				la[i][j] = la[p][j - 1];
				ld[i][j] = min(n, ld[i][j - 1] + ld[p][j - 1]);
			}
			p = ne[i][j - 1];
			if (p){
				ne[i][j] = ne[p][j - 1];
				nd[i][j] = min(n, nd[i][j - 1] + nd[p][j - 1]);
			}
		}
	}
}
void init(int K, vector<int> R_vec){
	k = K;
	n = R_vec.size();
	for (int i = 1; i <= n; i++){
		::R[i] = R_vec[i - 1];
	}
	Main();
}
bool checkbig(int x, int y){
	int i, xx = x, delta = y - x, s;
	for (s = 0, i = L; i >= 0; i--){
		if (a[ne[x][i]] >= a[y]){
			s += nd[x][i];
			x = ne[x][i];
		}
	}
	if (s >= delta)
		return 1;
	for (s = 0, x = xx, i = L; i >= 0; i--){
		if (a[la[x][i]] >= a[y]){
			s += ld[x][i];
			x = la[x][i];
		}
	}
	if (s >= n - delta)
		return 1;
	return 0;
}
bool checksmall(int x, int y){
	int i, yy = y, delta = y - x, s;
	for (s = 0, i = L; i >= 0; i--){
		if (a[la[y][i]] >= a[x]){
			s += ld[y][i];
			y = la[y][i];
		}
	}
	if (s >= delta)
		return 1;
	for (s = 0, y = yy, i = L; i >= 0; i--){
		if (a[ne[y][i]] >= a[x]){
			s += nd[y][i];
			y = ne[y][i];
		}
	}
	if (s >= n - delta)
		return 1;
	return 0;
}
int compare_plants(int x, int y){
	x++;
	y++;
	if (a[x] > a[y])
		return checkbig(x, y) ? 1 : 0;
	return checksmall(x, y) ? -1 : 0;
}
相关推荐
你的冰西瓜2 小时前
C++中的forward_list容器详解
开发语言·c++·stl·list
无垠的广袤2 小时前
【FPB-RA6E2 开发板】Zephyr 串口打印 DHT11 温湿度
c++·单片机·串口通信·开发板·瑞萨·传感器·dht11
bbq粉刷匠2 小时前
Java二叉树基础提升
java·数据结构·算法
客梦2 小时前
数据结构--栈
数据结构·笔记
nju_spy2 小时前
12月力扣每日一题(划分dp + 单调栈 + 堆 + 会议安排)
算法·leetcode·二分查找·动态规划·滑动窗口·单调栈·最大堆
智算菩萨2 小时前
【Python机器学习】支持向量机(SVM)完全指南:从理论到实践的深度探索
算法·机器学习·支持向量机
中國龍在廣州2 小时前
2025,具身智能正在惩罚“持有者”
人工智能·深度学习·算法·自然语言处理·chatgpt
Tandy12356_2 小时前
手写TCP/IP协议——实现ping的响应
c语言·网络·c++·网络协议·tcp/ip·计算机网络
爱学习的capoo2 小时前
电气控制与PLC考点(自用)
算法