CSP计算机软件能力认证 2022年12月 题解

1. 现值计算

模拟即可

代码:

#include<bits/stdc++.h>
using namespace std;

signed main() {
	int n;
	double e;
	cin >> n >> e;
	vector<int> a(n + 1);
	double ans = 0;
	for(int i = 0; i <= n; i++) {
		cin >> a[i];
		ans += a[i] * pow(1. + e, -i);
	}
	cout << fixed << setprecision(10) << ans << "\n";
	return 0;
}

2. 训练计划

先把树建出来,dfs下去的时候记一下最早的时间,回溯的时候记录最晚时间。
代码:

#include<bits/stdc++.h>
using namespace std;

signed main() {
	int n, m;
	cin >> m >> n;
	vector<vector<int>> adj(n + 1);
	
	vector<int> t(n + 1), vis(n + 1);
	for(int i = 1; i <= n; i++) {
		int p; cin >> p;
		adj[p].push_back(i);
	}
	for(int i = 1; i <= n; i++) {
		cin >> t[i];
	}
	vector<int> early(n + 1), late(n + 1);
	function<void(int, int, int)> dfs = [&] (int u, int fa, int curt) {
		vis[u] = 1;
		early[u] = curt;
		late[u] = m - t[u] + 1;
		for(auto v : adj[u]) {
			dfs(v, u, curt + t[u]);
			late[u] = min(late[u], late[v] - t[u]);
		}
	};
	for(int i = 1; i <= n; i++) {
		if(!vis[i]) {
			dfs(i, 0, 1);
		}
	}
	int notwoline = 0;
	for(int i = 1; i <= n; i++) {
		cout << early[i] << " ";
		if(early[i] + t[i] - 1 > m) {
//			cerr << "fuck:" << i << "\n";
			notwoline = 1;
		}
	} 
	if(notwoline) {
		return 0;
	}
	cout << "\n";
	for(int i = 1; i <= n; i++) {
		cout << late[i] << " ";
	}
	
	return 0;
}

3. JPEG 解码

按照公式模拟即可

代码:

#include<bits/stdc++.h>
using namespace std;
const double pi = acos(-1);
signed main() {
	vector<vector<int>> Q(8, vector<int> (8));
	for(int i = 0; i < 8; i++) {
		for(int j = 0; j < 8; j++) {
			cin >> Q[i][j];
		}
	}
	int n; cin >> n;
	int T; cin >> T;
	int x, y;
	x = y = 0;
	        //右,左下,下,右上 
	int dx[] = {0, 1, 1, -1};
	int dy[] = {1, -1, 0, 1};
	int d = -1; 
	vector<vector<int>> M(8, vector<int> (8));
	for(int i = 1; i <= n; i++) {
		int cur = 0;
		cin >> cur;
		if(d == -1) {
			d = 0;
		} else if(d == 0) {
			if(x == 0) {
				d = 1;
			} else {
				d = 3;
			}
		} else if(d == 1) {
			if(x == 7) {
				d = 0;
			} else if(y == 0) {
				d = 2;
			}
		} else if(d == 2) {
			if(y == 0) {
				d = 3;
			} else {
				d = 1;
			}
		} else if(d == 3) {
			if(y == 7) {
				d = 2;
			} else if(x == 0) {
				d = 0;
			}
		}
		M[x][y] = cur;
		x += dx[d];
		y += dy[d];
	}
	auto MQ = M;
	for(int i = 0; i < 8; i++) {
		for(int j = 0; j < 8; j++) {
			MQ[i][j] *= Q[i][j];
		}
	}
	auto Mc = MQ;
	auto alpha = [&] (int u) {
		if(u == 0) {
			return sqrt(0.5);
		} else {
			return 1.0;
		}
	};
	for(int i = 0; i < 8; i++) {
		for(int j = 0; j < 8; j++) {
			double sum = 0;
			for(int ii = 0; ii < 8; ii++) {
				for(int jj = 0; jj < 8; jj++) {
					sum += alpha(ii) * alpha(jj) * MQ[ii][jj] * cos(pi / 8 * (i + 0.5) * ii) * cos(pi / 8 * (j + 0.5) * jj);
				}
			}
			sum /= 4;
			double temp = sum + 128;
			
			Mc[i][j] = min((int) (sum + 128.5), 255);
			Mc[i][j] = max(Mc[i][j], 0);
			assert(Mc[i][j] >= 0);
		}
	}
	for(int i = 0; i < 8; i++) {
		for(int j = 0; j < 8; j++) {
			if(T == 0) {
				cout << M[i][j] << ' ';
			} else if(T == 1) {
				cout << MQ[i][j] << " ";
			} else if(T == 2) {
				cout << Mc[i][j] << " ";
			} else {
				assert(0);
			}
		}
		cout << "\n";
	}
	return 0;
}

4. 聚集方差

树上启发式合并,用 multiset 维护当前的值的集合,用 val 记录当前的答案,每进来一个值现在 multiset 里面找前驱和后继,因为新进来的值可能对这俩造成影响,然后再把离自己近的加到答案里面。复杂度 O ( n log ⁡ 2 n ) O(n\log^2 n) O(nlog2n)

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define int long long
signed main() {
	int n; cin >> n;
	vector<vector<int>> adj(n + 1);
	vector<int> a(n + 1);
	for(int i = 2; i <= n; i++) {
		int p;
		cin >> p;
		adj[p].push_back(i);
	}
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	vector<int> hson(n + 1), top(n + 1), sz(n + 1);
	function<void(int)> dfs1 = [&] (int u) {
		sz[u] = 1;
		for(auto v : adj[u]) {
			dfs1(v);
			if(!hson[u] || sz[hson[u]] < sz[v]) {
				hson[u] = v;
			}
			sz[u] += sz[v];
		}	
	};
	function<void(int, int)> dfs2 = [&] (int u, int tp) {
		top[u] = tp;
		if(hson[u]) {
			dfs2(hson[u], tp);
		}
		for(int v : adj[u]) {
			if(v == hson[u]) continue;
			dfs2(v, v);
		}
	};
	dfs1(1);
	dfs2(1, 1);
//	cerr << "hson:";
//	for(int i = 1; i <= n; i++) {
//		cerr << hson[i] << " ";
//	}
//	cerr << "\n";
	multiset<int> st;
	ll val = 0;
	function<void(int, int)> calc = [&] (int u, int curhson) {
//		cerr << "calc:" << u << "\n";
		// st[i-1] st[i] ... a[u] =?= st[i+1] st[i+2]
		//it:                           *                 
		multiset<int>::iterator it = st.lower_bound(a[u]);
		ll cur = (st.size() == 0 ? 0 : (ll) 1e18);
		
		if(it != st.end()) {
			cur = min(cur, 1ll * (a[u] - *it) * (a[u] - *it));
		}
		
		if(it != st.begin()) {
			multiset<int>::iterator it_pre = prev(it);
			// st[i-1] st[i] ... a[u] =?= st[i+1] st[i+2]
		//it_pre:         *                           
			cur = min(cur, 1ll * (a[u] - *it_pre) * (a[u] - *it_pre));
		}
		auto update = [&] (ll a, ll b, ll c, ll d) {
			//               st[i-1]  st[i]  st[i+1]   a[u]
			ll origin = min(b - a, c - b);
			if(origin > abs(d - b)) {
				val -= 1ll * origin * origin;
				val += 1ll * (d - b) * (d - b);
			}
		};
		val += cur;
		
		if(st.size() == 1) {
			val += 1ll * (*st.begin() - a[u]) * (*st.begin() - a[u]);
		} else if(st.size() != 0) {
			if(it != st.begin()) {
				auto it_pre = prev(it);
				//     s[i]
				ll ta, tb, tc;
				if(it_pre != st.begin()) {
					ta = *prev(it_pre);
				} else {
					ta = -2e9;
				}
				tb = *it_pre;
				if(it != st.end()) {
					tc = *it;
				} else {
					tc = 2e9;
				}
				
				update(ta, tb, tc, a[u]);
			}
			if(it != st.end()) {
				ll ta, tb, tc;
				if(it != st.begin()) {
					ta = *prev(it);
				} else {
					ta = -2e9;
				}
				tb = *it;
				if(next(it) != st.end()) {
					tc = *next(it);
				} else {
					tc = 2e9;
				}
				update(ta, tb, tc, a[u]);
			}
			
			
		}
//		cerr << "calc_val:" << val << "\n";
		st.insert(a[u]);
		
		for(int v : adj[u]) {
			if(v == curhson) continue;
			calc(v, curhson);
		}
	};
	
	vector<ll> ans(n + 1);
	function<void(int, int)> dsu_on_tree = [&] (int u, int keep) {
//		cerr << "dsu_on_tree:" << u << " " << keep << "\n";
		for(int v : adj[u]) {
			if(v == hson[u]) continue;
			dsu_on_tree(v, 0);
		}
		if(hson[u]) dsu_on_tree(hson[u], 1);
		
		calc(u, hson[u]);
		ans[u] = val;
		if(!keep) {
			st.clear();
			val = 0;
		}
	};
	
	dsu_on_tree(1, 0);
	for(int i = 1; i <= n; i++) {
		cout << ans[i] << "\n";
	}
	return 0;
}

5. 星际网络

究极毒瘤题,线段树优化建图+CF464E
简单的来说,先用线段树优化建图,然后跑dijkstra
dij的边权用一个长度 1 0 5 10^5 105 的线段树维护,对于加法,直接线段树上二分单点加和区间清零即可,对于cmp,用线段树二分前缀hash找到最长公共前缀,比较下一位就行。
对于空间,容易发现都是在原来的基础上加的,用主席树动态开点可以解决。

太恶心了 没有代码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值