这是一个很菜的 Oier 的博客|

Hanx16Msgr

园龄:2年8个月粉丝:12关注:3

2023 NOI 春测 T1 ~ T3 题解

2023 NOI 春测 T1 ~ T3 题解

T1 涂色游戏

P9117 [春季测试 2023] 涂色游戏

Solution

考虑 Li 表示第 i 行最后一次被染成什么颜色,Ui 表示第 i 列最后一次被染成什么颜色,同时记录下这些操作的时间先后顺序。

那么对于最终的格子 (i,j),它的颜色就是 LiUj 中更晚的一个,简单判断一下然后输出即可。

Code
#include<bits/stdc++.h>

using namespace std;

constexpr int _N = 1e5 + 5;
int n, m, q;
pair<int, int> L[_N], U[_N];

void Init() {
	for (int i = 1; i <= n; ++i) {
		L[i] = make_pair(0, 0);
	}
	
	for (int i = 1; i <= m; ++i) {
		U[i] = make_pair(0, 0);
	}
}

void Solve() {
	cin >> n >> m >> q;
	Init();
	
	for (int i = 1, opt, x, y; i <= q; ++i) {
		cin >> opt >> x >> y;
		
		if (opt == 0) {
			L[x] = make_pair(y, i);
		} else {
			U[x] = make_pair(y, i);
		}
	}
	
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			if (L[i].second > U[j].second) {
				cout << L[i].first << ' ';
			} else {
				cout << U[j].first << ' ';
			}
		}
		
		cout << '\n';
	}
}

signed main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int T; cin >> T;
	
	while (T--) Solve();
}

T2 幂次

P9118 [春季测试 2023] 幂次

Solution

我就搬个原题的题解过来吧:CF955C Sad powers

Code
#include<bits/stdc++.h>
#define int long long

using namespace std;
using i64 = long long;

i64 n, a[100005];
int k;

inline long double Qpow(int x, int y) {
	long double res = 1, base = x;
	
	for (; y; y >>= 1, base *= base) {
		if (y & 1) {
			res *= base;
		}
	}
	
	return res;
}

inline int GetRoot(int x, int y) {
	int l = 1, r = x;
	
	while (l <= r) {
		int mid = (l + r) >> 1;
		
		if (Qpow(mid, y) > x) r = mid - 1;
		else l = mid + 1;
	}
	
	return r;
}

signed main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> n >> k;
	i64 res = 1;
	int lim = 0;
	
	for (int i = k; ; ++i) {
		int v = GetRoot(n, i);
		lim = i;
		
		if (v <= 1) break;
		
		a[i] = v - 1;
	}
	
	for (int i = lim - 1; i >= k; --i) {
		for (int j = i + i; j <= lim; j += i) {
			a[i] -= a[j];
		}
	}
	
	for (int i = k; i < lim; ++i) {
		res += a[i];
	}
	
	cout << res << '\n';
}

T3 圣诞树

P9119 [春季测试 2023] 圣诞树

很显然的一个结论就是连接的路径一定不能相交。证明考虑相交的时候交换两个顶点的顺序一定更优。

假设已经连接的点的集合为 S,那么 S 一定在凸多边形上是连续的,因此有一个很显然的 DP:设 f(i,j,0/1) 表示从 k 逆时针转选了 i 个,顺时针转选了 j 个,当前在左侧 / 右侧。转移很明显(用 L(x) 表示 k 逆时针开始的第 x 个,R(x) 表示顺时针的第 x 个):

f(i,j,0)f(i1,j,0)+dis(L(i1),L(i))f(i,j,0)f(i1,j,1)+dis(R(j),L(i))f(i,j,1)f(i,j1,0)+dis(L(i),R(j))f(i,j,1)f(i,j1,1)+dis(R(j1),R(j))

最终答案就是 min0i<nmin(f(i,ni1,0),f(i,ni1,1))

题目要求输出方案,那么就在转移的过程中再记录一个 from(i,j,0/1) 表示当前状态是又哪一个转移过来的,最后遍历输出即可。

Code
#include<bits/stdc++.h>

using namespace std;
using Ldouble = long double;

constexpr int _N = 1e3 + 5;
int n, K;

struct Node {
	Ldouble x, y;
} po[_N];

struct TriPair {
	int fir, sec, thi;
	
	TriPair() {}
	TriPair(int fir, int sec, int thi) : fir(fir), sec(sec), thi(thi) {}
};

Ldouble f[_N][_N][2];
TriPair from[_N][_N][2];

inline Ldouble Sqr(Ldouble x) 
	{return x * x;}

inline Ldouble Dist(int i, int j) 
	{return sqrt(Sqr(po[i].x - po[j].x) + Sqr(po[i].y - po[j].y));}

inline int Lp(int x)
	{return K - x <= 0 ? K - x + n : K - x;}

inline int Rp(int x)
	{return K + x > n ? K + x - n : K + x;}

void Output(TriPair cur) {
	if (cur.fir == 0 && cur.sec == 0)
		return cout << K << ' ', void();
	
	Output(from[cur.fir][cur.sec][cur.thi]);
	
	if (cur.thi) cout << Rp(cur.sec) << ' ';
	else cout << Lp(cur.fir) << ' ';
}

signed main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> n;
	
	for (int i = 1; i <= n; ++i)
		cin >> po[i].x >> po[i].y;
	
	double tmpMax = -1e8;
	
	for (int i = 1; i <= n; ++i)
		if (po[i].y > tmpMax)
			tmpMax = po[i].y, K = i;
	
	for (int i = 0; i <= n; ++i)
		for (int j = 0; j <= n; ++j)
			f[i][j][0] = f[i][j][1] = 1e18;
			
	f[0][0][0] = f[0][0][1] = 0;
	Ldouble val;
	
	for (int i = 0; i < n; ++i) {
		for (int j = 0, jend = n - j; j < jend; ++j) {
			if (i) {
				val = f[i - 1][j][0] + Dist(Lp(i - 1), Lp(i));
				
				if (f[i][j][0] > val) 
					f[i][j][0] = val, from[i][j][0] = TriPair(i - 1, j, 0);
				
				val = f[i - 1][j][1] + Dist(Rp(j), Lp(i));
				
				if (f[i][j][0] > val) 
					f[i][j][0] = val, from[i][j][0] = TriPair(i - 1, j, 1);
			}
			
			if (j) {
				val = f[i][j - 1][0] + Dist(Lp(i), Rp(j));
				
				if (f[i][j][1] > val) 
					f[i][j][1] = val, from[i][j][1] = TriPair(i, j - 1, 0);
				
				val = f[i][j - 1][1] + Dist(Rp(j - 1), Rp(j));
				
				if (f[i][j][1] > val) 
					f[i][j][1] = val, from[i][j][1] = TriPair(i, j - 1, 1);
			}
		}
	}
	
	Ldouble ans = 1e18;
	TriPair pos;
	
	for (int i = 0; i < n; ++i) {
		if (ans > f[i][n - i - 1][0]) 
			ans = f[i][n - i - 1][0], pos = TriPair(i, n - i - 1, 0);
		
		if (ans > f[i][n - i - 1][1])
			ans = f[i][n - i - 1][1], pos = TriPair(i, n - i - 1, 1);
	}
	
	Output(pos);
}
posted @   Hanx16Msgr  阅读(361)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起