2019 NOIp提高组/CSP-S Day1 试做

2019 NOIp提高组/CSP-S DAY1 试做

按学长说的,刷一刷 NOIp 的题,然后就从洛谷里直接找到了2019年的题,按顺序先刷DAY1的,结果做到一半才想起来,去年的题好像不大对劲,严格说应该是CSP-S 2019……算了都已经开始了,至少把 D1 的先做了吧……


D1T1 格雷码

题目描述

下方传送门
题目链接
上方传送门

思路分析

  • zz找规律题,硬是傻眼了半天。
  • 还是得先好好读题。对于每次我们得出的格雷码,都可以分两半组成,前一半都是 \(0\) 开头的,而后一半都是 \(1\) 开头的。以这个规律为突破口。
  • 枚举一下 \(n=4\) 时的答案,大概是这样的
0000 0001 0011 0010 0110 0111 0101 0100
1100 1101 1111 1110 1010 1011 1001 1000
  • 这样就不难想到将格雷码分而治之(即分治),依循上面的规律已经得出第一位,那么第二位发现稍微有了一些变化。发现如果我们从后半段进行分治的话,规律正好反了过来,但其实大同小异
  • 虽然是D1T1,但做起来并没想象中的轻松,后来大致扫了一下题解,好像没几个我这么做的,都是一些奇奇怪怪的规律。
  • 另外求平方时别用左移别用左移!!!因为最高只能左移32位,就这破东西卡了我半个小时改来改去,然后我输出了一下1<<43的结果发现事情不大对劲。

Code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll unsigned long long //2^64 long long会炸
using namespace std;
inline ll read(){
	ll x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
ll n,k;
int main(){
	n = read(),k = read();
	bool flag = 1; //flag标记是否需要倒转规律
	ll res = pow(2,n-1); 
	while(res){
		if(k>=res){
			flag?putchar('1'),flag=0:putchar('0');
			k-=res;
		}
		else flag?putchar('0'):putchar('1'),flag=1;
		res>>=1;
	}
	return 0;
}

D1T2 括号树

题目描述

下方传送门
题目链接
上方传送门

思路分析

  • 这个没啥可说的……括号匹配当然要想到压栈弹栈,只是放树上了,并无大碍
  • 唯一难点就是递归回溯的时候不太好想,其实反过来即可,即清空所进行的操作,这样保证在回溯时回到原来的状态
  • 个人感觉T1比这题坑……

详见代码

Code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define N 500010
#define int long long
using namespace std;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,fa[N],head[N],sum[N],pre[N],sta[N],top;
char s[N];
struct edge{
	int to,next;
}e[N];
int len;
void addedge(int u,int v){
	e[++len].to = v;
	e[len].next = head[u];
	head[u] = len;
}
void dfs(int u){
	int res = 0;
	if(s[u]=='(')sta[++top] = u; //压进栈里等待匹配
	else{ //遇到')'就可以从栈里拿出括号来匹配了
		if(top){
			res = sta[top];
			pre[u] = pre[fa[res]]+1; //在左括号的父亲的基础上又增加了1对
			top--;
		}
	}
	sum[u] = sum[fa[u]]+pre[u];
	for(int i = head[u];i;i=e[i].next){
		int v = e[i].to;
		dfs(v);
	}
	if(res)sta[++top] = res; //拿出来了再放回去,不然你会像我一样获得85分的好成绩
	else if(top)top--; //压进去了再弹出去
}
signed main(){
	n = read();
	scanf("%s",s+1);
	for(int i = 2;i <= n;i++){
		fa[i] = read();
		addedge(fa[i],i);
	}
	dfs(1);
	int ans = 0;
	for(int i = 1;i <= n;i++)ans ^= i*sum[i];
	printf("%lld\n",ans);
	return 0;
}

D1T3

下方传送门
题目链接
上方传送门

  • 这tm是道黑题???看了看题,目测只会打10分暴力,做个球,咕了咕了。

总结

  • T1 题目那么长看着挺唬人的,而且乍一眼看上去也没什么思路,这时候还是反复读读题,找一找规律
  • T2 思路很简单但还是有些细节要处理的,比如我的85分
  • 这年的题不是很“正宗”,所以D2可能会咕掉,而转去做其他年份的题

另附整理的洛谷2019年提高组题单,有兴趣可以做一做:NOIp2019

posted @ 2020-08-15 11:21  HH_Halo  阅读(378)  评论(0编辑  收藏  举报