$CSP\ 2019\ Day1$ 模拟考试 题解报告

2021/6/2 18:51:31

本文主要是介绍$CSP\ 2019\ Day1$ 模拟考试 题解报告,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录
  • $CSP\ 2019\ Day1$ 模拟考试 题解报告
    • 得分情况
    • 考试过程
    • 题解
      • $T1$ 格雷码
      • $T2$ 括号树
      • $T3$ 树上的数

\(CSP\ 2019\ Day1\) 模拟考试 题解报告

得分情况

\(T1\) \(100\ Pts\)

\(T2\) \(55\ Pts\)

\(T3\) \(0\ Pts\)

总分: \(155\ Pts\)

考试过程

读完题 先拿 \(T1\) 手摸样例半个多小时 上了个厕所出结论 过大样例 转 \(T2\) 看到有链的数据 搞了一个很诡异的思路 特判出来先把链的写了 然后转正解 捣鼓许久 (赛后发现自己的处理方法较为诡异 并不能通过) 小样例都能过 大样例爆栈被卡 反复调 过不去 弃掉 转 \(T3\) 读入不会处理 然后就没法写 凄惨爆零

题解

\(T1\) 格雷码

\[k \oplus \lfloor \frac k2 \rfloor \]

代码

/*
  Time: 5.30
  Worker: Blank_space
  Source: 
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#define int unsigned long long
/*--------------------------------------头文件*/
int n, k, ans;
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/

/*----------------------------------------函数*/
signed main() {
	freopen("code.in","r",stdin);
	freopen("code.out","w",stdout);

    n = read(); k = read(); ans = k >> 1 ^ k;
    for(int i = n; i; i--)
	if(1ll << i - 1 & ans) putchar('1'); else putchar('0');
    
	fclose(stdin);
	fclose(stdout);
	return 0;
}
/*
半个小时 上了个厕所 突然悟了 
63 123321
000000000000000000000000000000000000000000000010001000101100101
悟了 
k >> 1 ^ k
过大样例 开 ull 
*/

\(T2\) 括号树

维护一个栈 遇到左括号直接入栈 栈中维护点标号 遇到右括号 且 栈中有东西 匹配成功一个 退栈 累加到来自父节点匹配成功的数量上 再统计贡献即可 退栈的时候记录一下退栈的点 由于是一棵树 在处理完一条链转到另一条链的时候要将多退的点再入栈

代码

/*
  Time: 5.30
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#define int long long
/*--------------------------------------头文件*/
const int B = 5e5 + 7;
const int C = 1e6 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int n, st[B], top, sum[B], ans, fa[B], lst[B];
char s[B];
struct edge {int v, nxt;} e[C];
int head[B], ecnt;
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
void add_edge(int u, int v) {e[++ecnt] = (edge){v, head[u]}; head[u] = ecnt;}
void dfs(int u) {
	int tmp = 0;
	if(s[u] == '(') st[++top] = u;
	else if(top) tmp = st[top--], lst[u] = lst[fa[tmp]] + 1;
	sum[u] = sum[fa[u]] + lst[u];
	for(int i = head[u], v = e[i].v; i; i = e[i].nxt, v = e[i].v) dfs(v);
	if(tmp) st[++top] = tmp; else if(top) --top;
}
/*----------------------------------------函数*/
signed main() {
	freopen("brackets.in","r",stdin);
	freopen("brackets.out","w",stdout);

    n = read(); scanf("%s", s + 1);
    for(int i = 2; i <= n; i++)
    {
    	int x = read(); fa[i] = x;
    	add_edge(x, i);
    }
    dfs(1);
    for(int i = 1; i <= n; i++) ans ^= sum[i] * i;
    printf("%lld", ans);
    
	fclose(stdin);
	fclose(stdout);
	return 0;
}
/*
5
(()()
1 1 2 2

10
()())()()))
1 2 2 1 5 6 6 6 6 9

深搜被卡
爆栈 
大数据根本过不去
那个链的好像也会被卡
15 - 50 
自己造了两组小样例倒是过了 
弃
*/

\(T3\) 树上的数

\(10\ Pts\) 暴力

枚举删除每一条边的顺序 删完之后再扫一遍更新答案

代码

/*
  Time: 6.2
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*--------------------------------------头文件*/
const int A = 2e3 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
}
/*----------------------------------------文件*/
int T, n, a[A], ans[A], tmp[A];
struct edge {int v, nxt;} e[A << 1];
int head[A], ecnt, lcnt;
std::pair <int, int> l[A];
bool vis[A];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
void add_edge(int u, int v) {e[++ecnt] = (edge){v, head[u]}; head[u] = ecnt;}
void scan() {
	n = read(); ecnt = 0; lcnt = 0; maxdu = 0;
	for(int i = 1; i <= n; i++) a[read()] = i, head[i] = 0, du[i] = 0, ans[i] = n - i + 1;
	for(int i = 1; i < n; i++)
	{
		int x = read(), y = read();
		add_edge(x, y); add_edge(y, x); l[++lcnt] = std::make_pair(x, y);
	}
}
void update() {
	for(int i = 1; i <= n; i++) tmp[a[i]] = i;
	for(int i = 1; i <= n; i++)
		if(tmp[i] < ans[i]) {for(int j = 1; j <= n; j++) ans[j] = tmp[j]; break;}
		else if(tmp[i] > ans[i]) break;
}
void dfs(int t) {
	if(t == n) {update(); return ;}
	for(int i = 1; i < n; i++) if(!vis[i])
	{
		Swap(a[l[i].first], a[l[i].second]); vis[i] = 1;
		dfs(t + 1);
		Swap(a[l[i].first], a[l[i].second]); vis[i] = 0;
	}
}
void print() {for(int i = 1; i <= n; i++) printf("%d ", ans[i]); putchar('\n');}
void work() {
	scan();  dfs(1); print();
}
/*----------------------------------------函数*/
int main() {
	T = read(); while(T--) work();
	return 0;
}

\(35\ Pts\) 暴力 + 菊花图

当删去一条边的时候 设花心为 \(x\) 点 边连接的另一点为 \(y\) 点 \(y\) 点的数字会来到花心 \(x\) 点的数字会到 \(y\) 点 且固定在 \(y\) 点 也就是说 除花心之外 其他点固定了删边时花心的值 而本身的数移动到花心 成为下一个固定的值

设花心为 \(u\) 其他点依次为 \(p_1, p_2, p_3, ..., p_i, p_{n - 1}\) \(a_i\) 表示 \(i\) 点上的数字 当依次删掉这些边的时候 有 \(a_{u} \to a_{p_1}, a_{p_1} \to a_{p_2}, ..., a_{p_{n - 1}} \to a_{p_n}, a_{p_n} \to a_u\) 相当于形成了一个环 环上每个点的数字向后顺延一位 上面的 \(p_i\) 可以是 \(u\) 点以外的任意点 我们可以贪心的构造这个环 依次枚举数字 再枚举点 为了使移动合法 最后出现的一定是一个大环 而不能提前出现小环 且用过的点不能再被用 并查集维护

代码

/*
  Time: 6.2
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*--------------------------------------头文件*/
const int A = 2e3 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
}
/*----------------------------------------文件*/
int T, n, a[A], maxdu, du[A], ans[A], tmp[A], fa[A], p[A];
struct edge {int v, nxt;} e[A << 1];
int head[A], ecnt, lcnt;
std::pair <int, int> l[A];
bool vis[A];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
void add_edge(int u, int v) {e[++ecnt] = (edge){v, head[u]}; head[u] = ecnt;}
void scan() {
	n = read(); ecnt = 0; lcnt = 0; maxdu = 0;
	for(int i = 1; i <= n; i++) a[read()] = i, head[i] = 0, du[i] = 0, ans[i] = n - i + 1;
	for(int i = 1; i < n; i++)
	{
		int x = read(), y = read(); du[x]++; du[y]++;
		add_edge(x, y); add_edge(y, x); l[++lcnt] = std::make_pair(x, y);
		maxdu = Max(maxdu, Max(du[x], du[y]));
	}
}
void update() {
	for(int i = 1; i <= n; i++) tmp[a[i]] = i;
	for(int i = 1; i <= n; i++)
		if(tmp[i] < ans[i]) {for(int j = 1; j <= n; j++) ans[j] = tmp[j]; break;}
		else if(tmp[i] > ans[i]) break;
}
void dfs(int t) {
	if(t == n) {update(); return ;}
	for(int i = 1; i < n; i++) if(!vis[i])
	{
		Swap(a[l[i].first], a[l[i].second]); vis[i] = 1;
		dfs(t + 1);
		Swap(a[l[i].first], a[l[i].second]); vis[i] = 0;
	}
}
void solve1() {
	for(int i = 1; i <= n; i++) tmp[a[i]] = i, fa[i] = i, vis[i] = 0;
	for(int i = 1; i < n; i++) for(int j = 1; j <= n; j++) if(!vis[j] && find(tmp[i]) != find(j))
	{
		vis[j] = 1; p[tmp[i]] = j; fa[tmp[i]] = j;
		break;
	}
	for(int i = 1; i <= n; i++) if(!vis[i]) {p[tmp[n]] = i; break;}
	for(int i = 1; i <= n; i++) ans[i] = p[tmp[i]];
}
void print() {for(int i = 1; i <= n; i++) printf("%d ", ans[i]); putchar('\n');}
//i 点所存的数是 a[i] 
//i 数所在的点是 tmp[i] 
void work() {
	scan();
	if(n <= 10) dfs(1);
	else if(maxdu == n - 1) solve1();
	print();
}
/*----------------------------------------函数*/
int main() {
	T = read(); while(T--) work();
	return 0;
}

\(60\ Pts\) 暴力 + 菊花图 + 链

首先把这条链拎出来 从一段到另一端标号 一下默认点的编号从左到右递增

显然 每个数字只有移到左侧或移到右侧两种情况 注意这里说的是最终状态

考虑一个数字位于 \(x\) 点 这个数字的最终状态位于 \(y\) 点(\(y > x\)) 也就是说 \(y\) 点在 \(x\) 点右侧 那么 \(x\) 点右侧的边一定先于左侧的边被删除(否则 \(x\) 就跑左边回不来了) \(x\) 与 \(y\) 之间的边一定是由 \(x\) 到 \(y\) 依次删除 \(y\) 点右侧的边一定先于左侧被删除(否则 \(x\) 即使移到 \(y\) 点也会再被移走) 移到左侧的某个点同理

那么我们对于每个点维护一个标记 表示这个点是左侧的边先于右侧被删除(\(0\)) 还是右侧的边先于左侧被删除(\(1\)) 初始化为 \(2\)

从小到大逐一枚举每个数与每个点 如果一个点未被占有 尝试将这个数从本来的位置移动到枚举到的点 检查是否可以移动 如果可以 更新两点之间所有边的标记 并记录答案

/*
  Time: 6.2
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*--------------------------------------头文件*/
const int A = 2e3 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
}
/*----------------------------------------文件*/
int T, n, a[A], maxdu, du[A], ans[A], tmp[A], fa[A], p[A], cnt, mark[A];
struct edge {int v, nxt;} e[A << 1];
int head[A], ecnt, lcnt;
std::pair <int, int> l[A];
bool vis[A];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
void add_edge(int u, int v) {e[++ecnt] = (edge){v, head[u]}; head[u] = ecnt;}
void scan() {
	n = read(); ecnt = 0; lcnt = 0; maxdu = 0;
	for(int i = 1; i <= n; i++) a[read()] = i, head[i] = 0, du[i] = 0, ans[i] = n - i + 1;
	for(int i = 1; i < n; i++)
	{
		int x = read(), y = read(); du[x]++; du[y]++;
		add_edge(x, y); add_edge(y, x); l[++lcnt] = std::make_pair(x, y);
		maxdu = Max(maxdu, Max(du[x], du[y]));
	}
}
void update() {
	for(int i = 1; i <= n; i++) tmp[a[i]] = i;
	for(int i = 1; i <= n; i++)
		if(tmp[i] < ans[i]) {for(int j = 1; j <= n; j++) ans[j] = tmp[j]; break;}
		else if(tmp[i] > ans[i]) break;
}
void dfs(int t) {
	if(t == n) {update(); return ;}
	for(int i = 1; i < n; i++) if(!vis[i])
	{
		Swap(a[l[i].first], a[l[i].second]); vis[i] = 1;
		dfs(t + 1);
		Swap(a[l[i].first], a[l[i].second]); vis[i] = 0;
	}
}
void solve1() {
	for(int i = 1; i <= n; i++) tmp[a[i]] = i, fa[i] = i, vis[i] = 0;
	for(int i = 1; i < n; i++) for(int j = 1; j <= n; j++) if(!vis[j] && find(tmp[i]) != find(j))
	{
		vis[j] = 1; p[tmp[i]] = j; fa[tmp[i]] = j;
		break;
	}
	for(int i = 1; i <= n; i++) if(!vis[i]) {p[tmp[n]] = i; break;}
	for(int i = 1; i <= n; i++) ans[i] = p[tmp[i]];
}
void dfs2(int u, int pre) {
	p[u] = ++cnt;
	for(int i = head[u], v = e[i].v; i; i = e[i].nxt, v = e[i].v) if(v != pre) dfs2(v, u);
}
bool check(int x, int y, int k) {
	int u = Min(p[x], p[y]), v = Max(p[x], p[y]);
	if(mark[p[x]] == (k ^ 1)) return 0;
	for(int i = u + 1; i <= v - 1; i++) if(mark[i] == k) return 0;
	if(mark[p[y]] == (k ^ 1)) return 0;
	return 1;
}
void up_date(int x, int y, int k) {
	int u = Min(p[x], p[y]), v = Max(p[x], p[y]);
	if(p[x] != 1 && p[x] != n) mark[p[x]] = k;
	for(int i = u + 1; i <= v - 1; i++) mark[i] = k ^ 1;
	if(p[y] != 1 && p[y] != n) mark[p[y]] = k;
}
void solve2() {
	cnt = 0;
	for(int i = 1; i <= n; i++) if(du[i] == 1) {dfs2(i, 0); break;}
	for(int i = 1; i <= n; i++) tmp[a[i]] = i, mark[i] = 2, vis[i] = 0;
	for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(!vis[j] && p[tmp[i]] != p[j])
	{
		bool flag = 0;
		if(p[tmp[i]] < p[j]) {if(check(tmp[i], j, 1)) up_date(tmp[i], j, 1), flag = 1;}
		else {if(check(tmp[i], j, 0)) up_date(tmp[i], j, 0), flag = 1;}
		if(flag) ans[i] = j, vis[j] = 1;
	}
}
void print() {for(int i = 1; i <= n; i++) printf("%d ", ans[i]); putchar('\n');}
//i 点所存的数是 a[i] 
//i 数所在的点是 tmp[i] 
void work() {
	scan();
	if(n <= 10) dfs(1);
	else if(maxdu == n - 1) solve1();
	else if(maxdu == 2) solve2();
	print();
}
/*----------------------------------------函数*/
int main() {
	T = read(); while(T--) work();
	return 0;
}

\(100\ Pts\) 正解

咕了



这篇关于$CSP\ 2019\ Day1$ 模拟考试 题解报告的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程