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\n",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\n",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\n",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 树上的数
暂时弃疗。。。