// // // // // // // // // // // // // //

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

\(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\) 正解

咕了

posted @ 2021-06-02 18:30  Blank_space  阅读(57)  评论(1编辑  收藏  举报
// // // // // // //