引言

非常友好的一次新生赛,我能写出来的都不是什么难题,主要考查平常算法的积累,熟练度。 alt

A 王子公主请做此题

一个经典的染色题,注意到题目说某个格子相邻的格子颜色不一样,对应到树的结构应该是.

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define i64 long long
#define pf push_front
#define pb push_back
#define lowbit(x) (x & (-x))
const int inf = 1e9, N = 2e5 + 10, mod = 998244353;
const long long INF = 1e18;
const double pi = 3.1415926535;
vector<vector<int>>g(N), t(N);
int a[N], col[N], c[N];
bool f = true;

void dfs(int u, int fa) {
	for (int v : g[u]) {
		if (v == fa)
			continue;
		if (col[v] and col[v] != 3 - col[u]) {
			f = false;
		}
		if (c[a[v]] != 0 and c[a[v]] != 3 - col[u]) {
			f = false;
		}
		col[v] = 3 - col[u];
		c[a[v]] = 3 - col[u];
		dfs(v, u);
	}
}

void solve() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= n; i++) {
		if (a[i] == a[1]) {
			col[i] = 1;
		}
	}
	c[a[1]] = 1;
	for (int i = 1; i < n; i++) {
		int u, v;
		cin >> u >> v;
		g[u].pb(v);
		g[v].pb(u);
	}
	dfs(1, 1);
	cout << (f ? "Yes" : "No") << "\n";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int _ = 1;  //cin >> _;
	while (_--)
		solve();
	return 0;
}

这里我的思路是先把所有编号为的节点染色为1,然后以1为根节点遍历一遍树,根据要求,节点u与其子节点v颜色必然不一致,在dfs过程中判断一下染色是否发生冲突,只要冲突让即可

B 育成马娘选择中!

签到题没什么好说的

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define i64 long long
#define pf push_front
#define pb push_back
#define lowbit(x) (x & (-x))
const int inf = 1e9, N = 2e5, mod = 998244353;
const long long INF = 1e18;
const double pi = 3.1415926535;

void solve() {
	int n, m;
	cin >> n >> m;
	int p = 0;
	while (m > n) {
		m -= n;
	}
	cout << m << "\n";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int _ = 1;  //cin >> _;
	while (_--)
		solve();
	return 0;
}

C 杜教筛与min_25筛求莫比乌斯函数与个数函数的狄利克雷卷积——??函数的前缀和

诈骗题,题面太长了,懒得看了直接看后面一句话,奈何本人英语不好,wa了一发

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define i64 long long
#define pf push_front
#define pb push_back
#define lowbit(x) (x & (-x))
const int inf = 1e9, N = 2e5, mod = 998244353;
const long long INF = 1e18;
const double pi = 3.1415926535;

void solve() {
	cout << "euler";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int _ = 1;  //cin >> _;
	while (_--)
		solve();
	return 0;
}

D 糖完了

真的糖完了,看到这题我一眼就是求缩点,然后在求入度为0的点的个数就解决了,于是.....我忘记了模板,比赛时wa了2发才写出来,背模板还是太难了

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define i64 long long
#define pf push_front
#define pb push_back
#define lowbit(x) (x & (-x))
const int inf = 1e9, N = 2e5, mod = 998244353;
const long long INF = 1e18;
const double pi = 3.1415926535;
int n, tim, vis[250], scc;
vector<vector<int>>g(250), gra(250);
int dfn[250], low[250], col[250], deg[250];
stack<int>st;

void tarjan(int u) {
	dfn[u] = low[u] = ++tim;
	vis[u] = 1;
	st.push(u);
	for (int v : g[u]) {
		if (!dfn[v]) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
		} else if (vis[v]) {
			low[u] = min(low[u], low[v]);
		}
	}
	if (dfn[u] == low[u]) {
		scc++;
		int t = 0;
		do {
			t = st.top();
			st.pop();
			vis[t] = 0;
			col[t] = scc;
		} while (t != u);
	}
}

void solve() {
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		int k;
		vector<int>tx(n + 1);
		cin >> k;
		for (int j = 0; j < k; j++) {
			int x;
			cin >> x;
			if (tx[x])
				continue;
			tx[x] = 1;
			g[i].pb(x);
		}
	}
	for (int i = 1; i <= n; i++) {
		if (!dfn[i]) {
			tarjan(i);
		}
	}
	for (int u = 1; u <= n; u++) {
		for (int v : g[u]) {
			if (col[v] != col[u]) {
				gra[col[u]].pb(col[v]);
				//	cout << "q\n";
				deg[col[v]]++;
			}
		}
	}
//	cout << "q" << scc << "\n";
	int ans = 0;
	for (int i = 1; i <= scc; i++) {
		if (!deg[i]) {
			ans++;
		}
	}
	cout << ans << "\n";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int _ = 1;
	//cin >> _;
	while (_--)
		solve();
	return 0;
}

E 是非常暴力dfs求解

F 文化推演

简单讲解一下题意,这里给你个物品,每个物品有个数量,我们要求从中任选个物品的贡献之和,贡献定义为将这个物品放在展台上所需要的最少展台数。关于展台有两个约束,一个展台最多只能放两个,且放两个物品时,这两个物品的种类不能一样。我们先思考这个最少展台数怎么求。假定你选了个物品,物品总和为,这个物品中最大值是mx。首先由于展台上的物品必须各不相同,所以至少需要mx个展台,考虑剩下展台怎么放, 显然,就只需要mx个就搞定了。如果呢,手玩一组样例发现我们,结果是.这是一个很经典的贪心思想,感兴趣的同学可以写这个气球题

考虑数据范围 ,定义一个状态,表示前种物品,总和为的方案数 显然可以推出状态转移方程,+= ,求解过程中我们始终让为方案中的,所以先对a数组排序 初始状态为 = 1

代码:

#include <bits/stdc++.h>
#define lowbit(x) (x & - (x))
#define pii pair<int,int>
#define pil pair<int,long long>
#define pli pair<long long,int>
#define pss pair<string,string>
#define pll pair<long long,long long>
#define pdd pair<double,double>
#define fir first
#define sec second
#define MP make_pair
#define pb push_back
#define pf push_front
#define i64 long long
#define i128 __int128_t
#define ull unsigned long long
#define ld long double
#define ll long long
using namespace std; 
const int N = 3e5+100,M = 1e9,inf = 1e9,MOD=1e9+7,mod=998244353;
const long long INF = 1e18;
const double pi = 3.1415926535897932385,eps = 1e-9;
i64 dp[5005][5005];
int a[5005];
void solve(){
	int n;  cin >> n;
	int sum = 0, mx = 0;
	for (int i=1; i<=n; i++){
		cin >> a[i];
		sum += a[i];
	}
	sort(a+1,a+1+n);
	dp[0][0] = 1;  i64 ans = 0;
	for (int i=1; i<=n; i++){
		for (int j=0; j<=sum; j++){
			dp[i][j] = dp[i-1][j];
			if (j >= a[i]){
				ans = (ans + (j+a[i]+1)/2*dp[i][j]+mod)%mod;
			}
			else {
				ans = (ans + a[i]*dp[i][j]+mod)%mod;
			}
			if (j >= a[i]){
				dp[i][j] = (dp[i][j] + dp[i-1][j-a[i]]+mod)%mod;
			}
		}
	}
	cout << ans << "\n";
}		 
int main(){  
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int _ = 1; //cin >> _;
	while(_--) solve();
	return 0;
}

注意运算过程要取模

G 竞技场参赛中!

模拟题没什么好说的,总体思路是模拟题目求解敌我速度,算是中等偏下的模拟吧,不豪赤

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define i64 long long
#define pf push_front
#define pb push_back
#define lowbit(x) (x & (-x))
const int inf = 1e9, N = 2e5, mod = 998244353;
const long long INF = 1e18;
const double pi = 3.1415926535;

bool check(string s, string ty1, int x, int Len, int m, int l, int cnt) {
	if (x == 1)
		return true;
	if (x == 2 and s == "Classic")
		return true;
	if (x == 3 and (ty1 == "Qian" or ty1 == "Zhong") and Len - l >= 800)
		return true;
	if (x == 4 and ty1 == "Qian" and s == "Mile")
		return true;
	if (x == 5 and ty1 == "Hou")
		return true;
	if (x == 6 and ty1 == "Hou" and s == "Long")
		return true;
	if (x == 7 and ty1 == "Zhong")
		return true;
	if (x == 8 and cnt >= 3)
		return true;
	if (x == 9 and s == "Classic")
		return true;
	if (x == 10 and s == "Mile")
		return true;
	if (x == 11 and s == "Hou")
		return true;
	return false;
}

int get(int x) {
	if (x == 1)
		return 500;
	else if (x == 2)
		return 800;
	else if (x == 3)
		return 2000;
	else if (x == 4)
		return 1200;
	else if (x == 5)
		return 800;
	else if (x == 6)
		return 1200;
	else if (x == 7)
		return 800;
	else if (x == 8)
		return 1000;
	else
		return -800;

}

void solve() {
	string type;
	cin >> type;   // 赛道类型
	int B = 0, M, L, Len;
	if (type == "Mile") {
		M = 267;
		L = 1067;
		Len = 1600;
	} else if (type == "Classic") {
		M = 333;
		L = 1333;
		Len = 2000;
	} else {
		M = 533;
		L = 2133;
		Len = 3200;
	}
	vector<int>veca(5), vecb(5);
	for (int i = 0; i < 5; i++)
		cin >> veca[i];  // a属性
	// 速度0 耐力1 力量2 意志3 智力4 0-4
	string sa, sb;
	cin >> sa;  // a跑法
	int n, t;
	cin >> n;  // a技能数
	vector<int>a(n + 1);
	for (int i = 1; i <= n; i++)
		cin >> a[i];   // 技能编号


	for (int i = 0; i < 5; i++)
		cin >> vecb[i];
	cin >> sb;
	cin >> t;
	vector<int>b(t + 1);
	for (int i = 1; i <= t; i++) {
		cin >> b[i];
	}

	i64 va = veca[0], vb = vecb[0];   // a b初始速度
//	cout << va << " " << vb << "\n";
	if (type == "Mile") {
		if (veca[1] < 600) {
			va -= 500;
		}
		if (vecb[1] < 600)
			vb -= 500;
	} else if (type == "Classic") {
		if (veca[1] < 800)
			va -= 500;
		if (vecb[1] < 800)
			vb -= 500;
	} else {
		if (veca[1] < 1000)
			va -= 500;
		if (vecb[1] < 1000)
			vb -= 500;
	}
//	cout << va << " " << vb << "\n";
	if (sb == "Qian") {
		if (vecb[2] < 800)
			vb -= 500;
	} else if (sb == "Zhong") {
		if (vecb[2] < 1000)
			vb -= 500;
	} else {
		if (vecb[2] < 1200)
			vb -= 500;
	}

	if (sa == "Qian") {
		if (veca[2] < 800) {
			va -= 500;
			//	cout << "q\n";
		}
	} else if (sa == "Zhong") {
		if (veca[2] < 1000)
			va -= 500;
	} else {
		if (veca[2] < 1200)
			va -= 500;
	}
//	cout << va << " " << vb << "\n";
	for (int i = 1; i <= n; i++) {
		if (check(type, sa, a[i], Len, M, L, n)) {
			if (a[i] >= 1 and a[i] <= 8) {
				va += get(a[i]);
				//	cout << a[i] << "q\n";
				if (veca[3] >= 1100) {
					//	cout << "ttt\n";
					va += 500;
				}
			}
		}
	}
//	cout << va << "\n";
	for (int i = 1; i <= t; i++) {
		if (check(type, sb, b[i], Len, M, L, t)) {
			if (b[i] >= 1 and b[i] <= 8) {
				vb += get(b[i]);
				//	cout << b[i] << "w\n";
				if (vecb[3] >= 1100) {
					vb += 500;
				}
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		if (check(type, sa, a[i], Len, M, L, n)) {
			if (a[i] >= 9 and a[i] <= 11) {
				vb += get(a[i]);
				if (veca[4] >= 1100) {
					vb -= 500;
				}
			}
		}
	}
	for (int i = 1; i <= t; i++) {
		if (check(type, sb, b[i], Len, M, L, t)) {
			if (b[i] >= 9 and b[i] <= 11) {
				//	cout << b[i] << "w\n";
				va += get(b[i]);
				if (vecb[4] >= 1100) {
					va -= 500;
				}
			}
		}
	}
//	cout << va << " " << vb << "\n";
	cout << (va > vb ? "Manbo" : "Muri") << "\n";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int _ = 1;  //cin >> _;
	while (_--)
		solve();
	return 0;
}

H 银牌之梦

没什么好说的构造一个9行5列的矩阵就好了,特解还是比较好想的,在纸上画个图玩一玩填数字游戏就搞定了。注意到3个要求1.0 1 2数量相同(赛时没看到wa了一发) 2.不存在>=3个连续的相同的数字出现 3.每个数字在八联通的基础下是一个连通块

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define i64 long long
#define pf push_front
#define pb push_back
#define lowbit(x) (x & (-x))
const int inf = 1e9,N =2e5,mod = 998244353;
const long long INF = 1e18;
const double pi = 3.1415926535;
void solve(){
    cout << "01012\n";
    cout << "10121\n";
    cout << "10012\n";
    cout << "01121\n";
    cout << "10212\n";
    cout << "02021\n";
    cout << "20212\n";
    cout << "02021\n";
    cout << "20200";
}
int main(){
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int _ = 1;  //cin >> _;
    while(_--)solve();
    return 0;
}

I 白垩之子

遗憾题,赛后多加一个特判就过了 总结一下题意,给你个点,每个点有个对应的符文,在给你条边,u v相连如果 != 的话,对于集合就应该包含,对于v也是如此。所以问题就变成了:枚举每一个符文c,把所有的点i相连的点v的符文即加入到中,当然保证,这里直接用set处理。其实这样看是一个简单题,纯粹的枚举,奈何我赛时没想到为0的情况,导致枚举到了不存在的符文。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define i64 long long
#define pf push_front
#define pb push_back
#define lowbit(x) (x & (-x))
const int inf = 1e9, N = 1e6 + 100, mod = 998244353;
const long long INF = 1e18;
const double pi = 3.1415926535;
int k[N];
vector<vector<int>>g(N), gra(N);
void solve() {
	int n, m;
	cin >> n >> m;
	int tmx = 0;
	for (int i = 1; i <= n; i++) {
		cin >> k[i];
		tmx = max(tmx, k[i]);
		g[k[i]].pb(i);
	}
	for (int i = 1; i <= m; i++) {
		int u, v;
		cin >> u >> v;
		gra[u].pb(v);
		gra[v].pb(u);
	}
	int ans = inf, mx = -1;
	for (int c = 1; c <= tmx; c++) {
		set<int>se;
        if (g[c].size() == 0)continue;
		for (int u : g[c]) {
			for (int v : gra[u]) {
				if (k[v] == c)
					continue;
				se.insert(k[v]);
			}
		}
		int cnt = se.size();
		if (cnt > mx) {
			ans = c;
			mx = cnt;
		}
	}
	cout  << ans << "\n";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int _ = 1;  //cin >> _;
	while (_--)
		solve();
	return 0;
}

注意特判的情况,复杂度是

J 嘉豪的爱希批希

模拟题意即可,这题因为赛时数据有问题,可能卡掉了一部分同学。 记录一个值表示当前天数应该的训练量,如果就变成 否则就

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define i64 long long
#define pf push_front
#define pb push_back
#define lowbit(x) (x & (-x))
const int inf = 1e9, N = 2e5, mod = 998244353;
const long long INF = 1e18;
const double pi = 3.1415926535;

void solve() {
	i64 n, x, y, k;
	cin >> n >> x >> y >> k;
	i64 now = 1, day = 0;
	i64 sum = 0;
	bool f = false;
	while (sum < n) {
		day++;
		if (now >= x) {
			f = true;
		}
		if (f) {
			sum += y;
			continue;
		}
		sum += now;
		now *= k;
	}
	cout << day << "\n";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int _ = 1;  //cin >> _;
	while (_--)
		solve();
	return 0;
}

K 小果的数组

为数不多的思维题,这个题觉得还是非常有趣的,首先要明白是什么。观察到如果我们选择个数去用改变数组,那就可以把这个数都变成,此时产生的和为。题目让我们选一个子序列,很容易发现其实你可以随便选,基于贪心原则,我们肯定选前个最小的数求把这个数操作,再把剩下的数求和。对原数组去排序枚举选择前个数操作能产生的和,即求,用前缀和预处理一下排序后的数组

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define i64 long long
#define pf push_front
#define pb push_back
#define lowbit(x) (x & (-x))
const int inf = 1e9, N = 2e5, mod = 998244353;
const long long INF = 1e18;
const double pi = 3.1415926535;

void solve() {
	int n;
	cin >> n;
	vector<i64>a(n + 1), pre(n + 1);
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	sort(a.begin() + 1, a.end());
	for (int i = 1; i <= n; i++)
		pre[i] = pre[i - 1] + a[i];
	i64 ans = 0;
	for (int i = 0; i <= n; i++) {
		i64 res = 1ll * i * i + pre[n] - pre[i];
		ans = max(ans, res);
	}
	cout << ans << "\n";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int _ = 1;
	cin >> _;
	while (_--)
		solve();
	return 0;
}

注意i要从0开始枚举,还有会超出爆

L 博弈暂时没想到

M 四叠半印刷厂

题目背景太长了,我压根没看,直接读题目描述,抓住两个关键点,有区间修改,区间查询,线段树直接秒了。这里严肃批评24现役ACM学长,竟然不会默写一个最简单的区间修改,区间和查询的线段树板子。 知道线段树后,就常规模拟天数从0开始枚举,如果就特判一下区间带下关系就好了。 涉及到区间修改的只有b数组,a数组的区间和用前缀和预处理就行了 当然这题其实有不用线段树的做法,但学长是一个善于利用工具偷懒的人,直接套线段树模板就好了,值得一提的是我码线段树只用了12min,超级大脑!

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define i64 long long
#define pf push_front
#define pb push_back
#define lowbit(x) (x & (-x))
const int inf = 1e9, N = 2e6 + 10, mod = 998244353;
const long long INF = 1e18;
const double pi = 3.1415926535;
int n, m, k;
i64 a[N], b[N], pre[N];
i64 tag[N << 2], tr[N << 2];

void push_up(int i) {
	tr[i] = tr[i << 1] + tr[i << 1 | 1];
}

void build(int i, int l, int r) {
	if (l == r) {
		tr[i] = b[l];
		return;
	}
	int mid = (l + r) >> 1;
	build(i << 1, l, mid);
	build(i << 1 | 1, mid + 1, r);
	push_up(i);
}

void lazy(int i, int l, int r, int d) {
	tr[i] += (r - l + 1) * d;
	tag[i] += d;
}

void push_down(int i, int l, int r) {
	if (tag[i]) {
		int mid = (l + r) >> 1;
		lazy(i << 1, l, mid, tag[i]);
		lazy(i << 1 | 1, mid + 1, r, tag[i]);
		tag[i] = 0;
	}
}

void updata(int l, int r, int i, int pl, int pr, int d) {
	if (l <= pl and pr <= r) {
		tr[i] += (pr - pl + 1) * d;
		tag[i] += d;
		return;
	}
	push_down(i, pl, pr);
	int mid = (pl + pr) >> 1;
	if (l <= mid) {
		updata(l, r, i << 1, pl, mid, d);
	}
	if (r > mid) {
		updata(l, r, i << 1 | 1, mid + 1, pr, d);
	}
	push_up(i);
}

i64 query(int l, int r, int i, int pl, int pr) {
	if (l <= pl and pr <= r) {
		return tr[i];
	}
	push_down(i, pl, pr);
	i64 res = 0;
	int mid = (pl + pr) >> 1;
	if (l <= mid) {
		res += query(l, r, i << 1, pl, mid);
	}
	if (r > mid) {
		res += query(l, r, i << 1 | 1, mid + 1, pr);
	}
	return res;
}

void solve() {
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++) {
		cin >> a[i] >> b[i];
		pre[i] = pre[i - 1] + a[i];
	}
	build(1, 1, n);
	i64 ans = 0;
	for (int i = 0; i < m; i++) {
		int l, r;
		cin >> l >> r;
		if (i % k == 0) {
			if (query(l, r, 1, 1, n) >= pre[r] - pre[l - 1]) {
				continue;
			}
		}
		ans += (r - l + 1);
		updata(l, r, 1, 1, n, 1);
	}
	cout << ans << "\n";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int _ = 1;  //cin >> _;
	while (_--)
		solve();
	return 0;
}

惩罚24级ACM学长没码出线段树模板的罚抄十遍线段树代码,最后默写并背诵!!!

N 赛时没来得及看

O 四叠半算命

题目很简单,给你一个数不断把这个数变成他的数位和,直到长度为1,当然最后还要对9取模,赛时没看到wa了一发。实现方法有多种,这里贴一下我的代码参考。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define i64 long long
#define pf push_front
#define pb push_back
#define lowbit(x) (x & (-x))
const int inf = 1e9, N = 2e5, mod = 998244353;
const long long INF = 1e18;
const double pi = 3.1415926535;

void solve() {
	string t;
	cin >> t;
	while (t.size() > 1) {
		int res = 0;
		for (char i : t) {
			res += i - '0';
		}
		t = to_string(res);
	}
	int res = 0;
	for (char i : t) {
		res += i - '0';
	}
	res %= 9;
	cout << res << "\n";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int _ = 1;  //cin >> _;
	while (_--)
		solve();
	return 0;
}

总结

总体来说,感觉题目非常不错,考虑本次参赛是全院要求,学长们出题还是比较仁慈的,给了4题签到题。做出4题以上的都是不错的。