CSP2019-S 复赛游记

Day1:

T1 格雷码:

题目链接

在考场上的时候,推了十几分钟大概搞出了思路,就是倒着模拟格雷码构造的过程,一位一位推下来。但当时不知道怎么用 unsigned long long,也不知道它的范围比普通 long long 要大一点,刚好符合这道题的条件。

于是考场上的方法如果不卡的话有95分,卡的话能被卡到80分。。。


ull 大致用法:

定义:unsigned long long n;
输入输出:cout 或 printf("%llud",n);
其他与普通 long long 一样。

AC代码:

#include<bits/stdc++.h>
#define LL unsigned long long
using namespace std;
LL n,K;
namespace P1{
	string ans;
	LL f2[70];
	void solve(){
		f2[0]=1;
		for(LL i=1;i<=63;i++)f2[i]=f2[i-1]*2;
		f2[64]=f2[63]-1+f2[63];
		scanf("%llud",&K);
		LL nw=n;
		while(nw){
			if(K>=f2[nw-1]){
				ans+='1';
				K-=f2[nw-1];
				K=f2[nw-1]-K-1;
			}
			else ans+='0';
			nw--;
		}
		cout<<ans;
	}
}
int main(){
	scanf("%llud",&n);
	P1::solve();
	return 0;
}

里面细节还是挺多的,特别是预处理2的幂的部分。

T2 括号树:

题目链接

考场上居然只想到了 (O(n^2)) 的做法,连链的情况都没想到,也不知道是怎么了。但在luogu上能水到95分 震惊

其实链的情况还是非常好想的,找几组样例推一下就好了,找一下规律,大概是一个前缀和的思想。

正解在树上,和链有一些不一样,要用到类似于撤回的思想,即在栈中纪录每一次的压入弹出,回溯的时候撤回回去。

AC代码:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL N=500005;
LL n,val[N];
char s[N];
vector<LL>edge[N];
namespace P1{//n^2暴力
	LL fa[N],dp[N],ans[N];
	LL calc(LL x,LL v){
		LL res=0,nw=x;
		while(nw){
			nw=fa[nw];
			if(dp[nw]-dp[x]<0)break;
			if(dp[nw]==dp[x])res++;
		}
		return res;
	}
	void dfs(LL x,LL f,LL la){
		fa[x]=f;dp[x]=dp[f]+val[x];
		LL nw=calc(x,dp[x]);
		ans[x]=nw+la;
		for(LL i=0;i<edge[x].size();i++){
			LL y=edge[x][i];
			if(y==f)continue;
			dfs(y,x,la+nw);
		}
	}
	void solve(){
		dfs(1,0,0);LL res=0;
		for(LL i=1;i<=n;i++)res^=i*ans[i];
		printf("%lld
",res);
	}
}
namespace P2{//链
	LL stk[N],top,f[N],a[N];
	void solve(){
		for(LL i=1;i<=n;i++){
			if(val[i]==-1&&top){
				a[i]=a[stk[top]-1]+1;
				top--;
			}
			else if(val[i]==1)stk[++top]=i;
			f[i]=f[i-1]+a[i];
		}
		LL res=0;
		for(LL i=1;i<=n;i++)res^=i*f[i];
		printf("%lld
",res);
	}
}
namespace P3{//正解
	LL stk[N],top,a[N],fa[N],f[N];
	void dfs(LL x,LL Fa){
		fa[x]=Fa;
		LL f1=0,f2=0;
		if(val[x]==-1&&top){
			f1=stk[top];
			a[x]=a[fa[stk[top]]]+1;
			top--;
		}
		else if(val[x]==1)stk[++top]=x,f2=1;
		f[x]=f[fa[x]]+a[x];
		for(LL i=0;i<edge[x].size();i++){
			LL y=edge[x][i];
			if(y==Fa)continue;
			dfs(y,x);
		}
		if(f1)stk[++top]=f1;
		else if(f2)top--;
	}
	void solve(){
		dfs(1,0);
		LL res=0;
		for(LL i=1;i<=n;i++)res^=i*f[i];
		printf("%lld
",res);
		exit(0);
	}
}
int main(){
	scanf("%lld%s",&n,s+1);
	for(LL i=1;i<=n;i++){
		if(s[i]=='(')val[i]=1;
		else val[i]=-1;
	}bool flag=1;
	for(LL i=2,x;i<=n;i++){
		scanf("%lld",&x);
		edge[x].push_back(i);
		edge[i].push_back(x);
		if(x!=i-1)flag=0;
	}
	P3::solve();
	if(flag)P2::solve();
	else P1::solve();
	return 0;
}

T3 树上的数

暂时弃疗。。。

原文地址:https://www.cnblogs.com/tangzhiyang/p/11964242.html