CodePlus 第五次网络赛 掐指会算

本文解析了NOIP赛前练习的四道题目,包括矩阵异或问题、逻辑树构造、监控中心问题和法师问题。详细介绍了每道题目的解题思路和代码实现,涉及递推、树形DP、图论和计算几何等算法。

失踪人口暂时回归。
临近 NOIP 了,退役选手准备打一打 Div.2 来练练手(应该不是天气冷了,没衣服穿了
游戏体验差,OJ 又和第一次一样卡了半天。


T1 我有矩阵,你有吗?

根据异或的性质,不难发现 AAA 矩阵的每行每列最多只能异或一次。
所以我们可以假设 AAA 矩阵的第一行是否被异或了,然后把所有状态递推出来,最后判断一下是否符合题设。

#include <bits/stdc++.h>
using namespace std;
int F()
{
	int x = 0; char ch; bool minus = 0;
	while(ch = getchar(), (ch > '9' || ch < '0') && ch != '-');
	ch == '-' ? minus = 1 : x = ch - '0';
	while(ch = getchar(), ch <= '9' && ch >= '0') x = x * 10 + ch - '0';
	return minus ? -x : x;
}

int n, m, x[1010], y[1010], A[1010][1010], B[1010][1010];
int main()
{
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j)
			scanf("%d", &A[i][j]);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j)
			scanf("%d", &B[i][j]);
	for(int i = 1; i <= m; ++i) if(A[1][i] != B[1][i]) y[i] = 1;
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j)
			if((A[i][j] ^ y[j] ^ x[i]) != B[i][j]) x[i] ^= 1;
	bool flag = 0;
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j)
			if((A[i][j] ^ x[i] ^ y[j]) != B[i][j])
				flag = 1;
	if(!flag){ puts("Koyi"); return 0; }
	memset(x, 0, sizeof(x)); memset(y, 0, sizeof(y));
	x[1] = 1;
	for(int i = 1; i <= m; ++i) if(A[1][i] == B[1][i]) y[i] = 1;
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j)
			if((A[i][j] ^ y[j] ^ x[i]) != B[i][j]) x[i] ^= 1;
	flag = 1;
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j)
			if((A[i][j] ^ x[i] ^ y[j]) != B[i][j])
				flag = 1;
	if(!flag){ puts("Koyi"); return 0; }
	puts("Budexing");
	return 0;
}

T2 逻辑树

一开始没看到在询问的都是叶结点,想了半天。

我想到的是一种构造方式,这种构造方式可以保证所有询问序列都是必要的,且根结点的取值一定为 111

假设只有三个点(一个根和两个叶子,aaa 点为先询问的叶子,bbb 为后询问的),假设根的运算符为 and ,那么 aaa 显然要取值为 111,才能保证询问 bbb 时不会跳过,若为 or,则 aaa 要为 000,按照这样的取值,根结点的取值就依赖于 bbb 了。

如果有很多点,我们可以按照询问的叶子的顺序,每次找到这个叶子的祖先第一个取值还未被确定的点(即这个点的取值不依赖与任意一个叶子),然后如果是 and,则该叶子取值为 111,为 or 则为 000

需要注意的是如果是最后一个叶子,那么对应的祖先一定是根结点,而此时根结点的取值依赖与最后一个叶子的取值,所以最后一个叶子取值为 111

这样做的复杂度为 O(n)O(n)O(n),应为每一个点都只会被找两次。

#include <bits/stdc++.h>
using namespace std;
#define Min(_A, _B) (_A < _B ? _A : _B)
#define Max(_A, _B) (_A > _B ? _A : _B)
int F()
{
	int x = 0; char ch; bool minus = 0;
	while(ch = getchar(), (ch > '9' || ch < '0') && ch != '-');
	ch == '-' ? minus = 1 : x = ch - '0';
	while(ch = getchar(), ch <= '9' && ch >= '0') x = x * 10 + ch - '0';
	return minus ? -x : x;
}

const int MaxN = 500010;
int Next[MaxN << 2], Point[MaxN << 1], To[MaxN << 2], q, P[MaxN << 1];
void Add(int u, int v)
{
	Next[++q] = Point[u]; Point[u] = q; To[q] = v;
	Next[++q] = Point[v]; Point[v] = q; To[q] = u;
}
int N, f[MaxN << 1][2], p[MaxN << 1][2], w[MaxN << 1], l[MaxN << 1], r[MaxN << 1], fa[MaxN << 1];
void dfs(int u, int from)
{
	fa[u] = from;
	for(int j = Point[u]; j; j = Next[j]) if(To[j] != from)
	{
		if(!l[u]) l[u] = To[j]; else r[u] = To[j];
		dfs(To[j], u);
	}
}
int ans[MaxN], pre[MaxN], Q[MaxN << 1], cnt;
bool vis[MaxN];
int find(int u){ return u == pre[u] ? u : pre[u] = find(pre[u]); }
int main()
{
	scanf("%d", &N);
	for(int i = 1; i < N; ++i) scanf("%d", &w[i + N]);
	for(int i = 1; i <= 2 * N - 2; ++i) Add(F(), F());
	for(int i = 1; i <= N; ++i) P[i] = F();
	dfs(N + 1, 0);
	for(int i = 1; i <= N; ++i) pre[i] = i;
	for(int i = 1; i <= N; ++i)
	{
		vis[P[i]] = 1;
		int t = P[i];
		while(fa[t] && vis[l[fa[t]]] && vis[r[fa[t]]]) 
		{
			t = fa[t];
			vis[t] = 1;
		}
		if(fa[t]) ans[P[i]] = !w[fa[t]];
		else ans[P[i]] = 1;
	}
	
	for(int i = 1; i <= N; ++i) printf("%d", ans[i]);
	return 0;
}

T3 监控中心

认真分析题目发现,题目其实是给定一张图,图中的每个点要么属于 AAA,要么属于 BBB,告诉你哪些边连接着不同集合中的元素,求 ∣A∣|A|A

首先看子任务 111,一条链。我们发现如果有连续的几个 AAA 中的元素被夹在 BBB 中,那么我们可以利用后缀和的方式,将两个边界处的元素的位置相减,得到被夹在中间的 AAA 中元素的个数。

再来看子任务 2,32,32,3,一棵树。道理和子任务 111 是类似的,我们只需要将后缀和改为子树和,然后也可以利用加减来得出元素的个数。需要注意你求的集合是否为 AAA

子任务 444,一张图。找出任意的生成树,按照树来做。因为图给出的边有很多是没有价值的,多余的。

#include <bits/stdc++.h>
using namespace std;
int F()
{
	int x = 0; char ch; bool minus = 0;
	while(ch = getchar(), (ch > '9' || ch < '0') && ch != '-');
	ch == '-' ? minus = 1 : x = ch - '0';
	while(ch = getchar(), ch <= '9' && ch >= '0') x = x * 10 + ch - '0';
	return minus ? -x : x;
}
#define Abs(_A) (_A > 0 ? _A : -(_A))
const int MaxN = 1000010, MaxM = 2500010;
int n, m, Q[10000010];
struct Edge { int u, v; } e[MaxM];
int Next[MaxN << 1], To[MaxN << 1], Point[MaxN], q;
bool vis[MaxM];
void Add(int u, int v)
{
	Next[++q] = Point[u]; Point[u] = q; To[q] = v;
	Next[++q] = Point[v]; Point[v] = q; To[q] = u;
}
int l[MaxN], sum[MaxN], dfn_index;
void dfs(int u, int from)
{
	l[u] = ++dfn_index; ++sum[u];
	for(int j = Point[u]; j; j = Next[j]) if(To[j] != from)
	{
		dfs(To[j], u);
		sum[u] += sum[To[j]];
	}
}
int pre[MaxN];
int find(int u){ return u == pre[u] ? u : pre[u] = find(pre[u]); }
int main()
{
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= m; ++i) e[i] = (Edge){F(), F()};
	for(int i = 1; i <= n; ++i) pre[i] = i;
	for(Edge *i = e + 1; i <= e + m; ++i)
	{
		int X = find(i->u), Y = find(i->v);
		if(X != Y)
		{
			pre[X] = Y;
			Add(i->u, i->v);
			vis[i - e] = 1;
		}
	}
	dfs(1, 0);
	int q;
	scanf("%d", &q);
	for(int i = 1; i <= q; ++i)
	{
		int c, tot = 0, pos = 0, tmp = 2147483647; scanf("%d", &c);
		for(int j = 1; j <= c; ++j) 
		{
			scanf("%d", &Q[j]);
			if(!vis[Abs(Q[j])]) continue;
			if(l[e[Abs(Q[j])].u] < tmp) tmp = l[e[Abs(Q[j])].u], pos = e[Abs(Q[j])].u;
			if(l[e[Abs(Q[j])].v] < tmp) tmp = l[e[Abs(Q[j])].v], pos = e[Abs(Q[j])].v;
		}
		bool flag = 1;
		for(int j = 1; j <= c; ++j)
		{
			int u, v;
			if(!vis[Abs(Q[j])]) continue;
			if(Q[j] > 0) u = e[Q[j]].u, v = e[Q[j]].v;
			if(Q[j] < 0) u = e[-Q[j]].v, v = e[-Q[j]].u;
			if(pos == v) flag = 0;
			if(l[u] < l[v]) tot -= sum[v];
			else tot += sum[u];
		}
		if(!flag) tot = n - tot;
		printf("%d\n", Abs(tot));
	}
	return 0;
}

T4 法师

目测一道计算几何题,Div.2 全场无人 AC,而且还没部分分(有我应该也写不出来)


rank 20- 应该是有件衣服过冬了。

(1)普通用户端(全平台) 音乐播放核心体验: 个性化首页:基于 “听歌历史 + 收藏偏好” 展示 “推荐歌单(每日 30 首)、新歌速递、相似曲风推荐”,支持按 “场景(通勤 / 学习 / 运动)” 切换推荐维度。 播放页功能:支持 “无损音质切换、倍速播放(0.5x-2.0x)、定时关闭、歌词逐句滚动”,提供 “沉浸式全屏模式”(隐藏冗余控件,突出歌词与专辑封面)。 多端同步:自动同步 “播放进度、收藏列表、歌单” 至所有登录设备(如手机暂停后,电脑端打开可继续播放)。 音乐发现与管理: 智能搜索:支持 “歌曲名 / 歌手 / 歌词片段” 搜索,提供 “模糊匹配(如输入‘晴天’联想‘周杰伦 - 晴天’)、热门搜索词推荐”,结果按 “热度 / 匹配度” 排序。 歌单管理:创建 “公开 / 私有 / 加密” 歌单,支持 “批量添加歌曲、拖拽排序、一键分享到社交平台”,系统自动生成 “歌单封面(基于歌曲风格配色)”。 音乐分类浏览:按 “曲风(流行 / 摇滚 / 古典)、语言(国语 / 英语 / 日语)、年代(80 后经典 / 2023 新歌)” 分层浏览,每个分类页展示 “TOP50 榜单”。 社交互动功能: 动态广场:查看 “关注的用户 / 音乐人发布的动态(如‘分享新歌感受’)、好友正在听的歌曲”,支持 “点赞 / 评论 / 转发”,可直接点击动态中的歌曲播放。 听歌排行:个人页展示 “本周听歌 TOP10、累计听歌时长”,平台定期生成 “全球 / 好友榜”(如 “好友中你本周听歌时长排名第 3”)。 音乐圈:加入 “特定曲风圈子(如‘古典音乐爱好者’)”,参与 “话题讨论(如‘你心中最经典的钢琴曲’)、线上歌单共创”。 (2)音乐人端(创作者中心) 作品管理: 音乐上传:支持 “无损音频(FLAC/WAV)+ 歌词文件(LRC)+ 专辑封面” 上传,填写 “歌曲信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值