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