考场错误、经验:
今天的前几题,难度比较小,但是我罚时有点多,这个需要改进
当做到博弈论的题目时,忘记了sg函数的相关知识定义,导致一直卡住
然后看了GH没什么人做,所以也没有仔细思考,一直卡在博弈论的题目上
这点应该注意,一道题目确定做不出来就要及时放弃,去做其他的题目
sg函数要注意,还有 n ∗ m ≤ 1 e 5 n*m \le 1e5 n∗m≤1e5要注意较小值一定 < 1 e 5 <\sqrt{1e5} <1e5,这个性质要注意,还有最后一题,看到两条没有点重合的路径,就应该想到点双连通分量,继而想到广义圆方树的做法
HackerRank - zero-move-nim
这道题目在nim游戏的基础上,增加了一个规则是,每堆石子可以有一次不取的操作
这样我们考虑各个游戏还是独立的,可以通过异或的方式得到总游戏的结果
然后我们考虑一个游戏,使用sg的定义,各个能到达状态的sg函数的mex
sg(0)=0
sg(1)=mex{sg(0),nim(1)}
sg(2)=mex{sg(1),nim(2)}
通过观察可以发现,我们奇数的sg值加1,偶数的减1
然后就是把各个游戏的sg异或起来
#include<bits/stdc++.h>
using namespace std;
int T,n;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int sg=0;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
x+=(x&1)?1:-1;
sg^=x;
}
if(sg==0) printf("L\n");
else printf("W\n");
}
return 0;
}
HackerRank - palindromic-table
因为 n ∗ m ≤ 1 e 5 n*m \le 1e5 n∗m≤1e5,可以得到 m i n ( n , m ) ≤ 1 e 5 min(n,m) \le \sqrt{1e5} min(n,m)≤1e5,所以我们可以枚举三个边,剩下的一个利用差分压位记录一下就可以了
#include<bits/stdc++.h>
using namespace std;
int n,m,Del[1000005];
vector <vector<int> > G,sum;
vector <vector<int> > sz(int n,int m)
{
vector <vector<int> > tmp(n+1);
for(int i=0;i<=n;i++) tmp[i].resize(m+1);
return tmp;
}
int pos[3000];
bool not_zero(int a,int b,int c,int d)
{
int res=sum[c][d]-sum[a-1][d]-sum[c][b-1]+sum[a-1][b-1];
// cerr<<res<<endl;
return res>1;
}
int gs(int v)
{
int res=0;
while(v)
{
res+=v&1;
v>>=1;
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
G=sz(n,m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&G[i][j]);
int rev=0;
if(n>m)
{
vector<vector<int> > T;
T=sz(m,n);
rev=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
T[j][i]=G[i][j];
G=T;
swap(n,m);
}
sum=sz(n,m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
sum[i][j]=(G[i][j]>0),sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
int ans=1,pa=1,pb=1,pc=1,pd=1;
vector <vector<vector<int> > > val(m+1);
// return 0;
for(int i=0;i<=m;i++)
{
val[i].resize(n+1);
for(int j=0;j<=n;j++)
val[i][j].resize(n+1);
}
int a,b,c,d;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
val[i][j][j]=(1<<G[j][i]);
for(int k=j+1;k<=n;k++)
{
val[i][j][k]=val[i][j][k-1]^(1<<G[k][i]);
if(gs(val[i][j][k])>1) continue;
a=j,b=i,c=k,d=i;
if(not_zero(a,b,c,d) && ans<(c-a+1)*(d-b+1))
ans=(c-a+1)*(d-b+1),pa=a,pb=b,pc=c,pd=d;
}
}
// // return 0;
// printf("%d\n",n);
// return 0;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
// cerr<<i<<" "<<j<<endl;
int v=0,nv,cnt=0;
pos[0]=1;
for(int k=1;k<=m;k++)
{
v^=val[k][i][j];
for(int dd=0;dd<10;dd++)
{
nv=v^(1<<dd);
if(!pos[nv]) continue;
a=i,b=pos[nv],c=j,d=k;
if(not_zero(a,b,c,d) && ans<(c-a+1)*(d-b+1))
ans=(c-a+1)*(d-b+1),pa=a,pb=b,pc=c,pd=d;
}
nv=v;
// cerr<<"!!";
if(!pos[nv])
{
pos[v]=k+1,Del[++cnt]=v;
continue;
}
a=i,b=pos[nv],c=j,d=k;
if(not_zero(a,b,c,d) && ans<(c-a+1)*(d-b+1))
ans=(c-a+1)*(d-b+1),pa=a,pb=b,pc=c,pd=d;
}
// continue;
for(int dd=1;dd<=cnt;dd++)
pos[Del[dd]]=0;
}
// return 0;
printf("%d\n",ans);
if(rev) printf("%d %d %d %d",pb-1,pa-1,pd-1,pc-1);
else printf("%d %d %d %d",pa-1,pb-1,pc-1,pd-1);
return 0;
}
HackerRank - bonnie-and-clyde
题目中提到了点双,考场上却没联想到圆方树,说明对连通性这部分还需要多加复习
对于一个点双,显然内部有不止一条道路,所以我们要求u,v,w三者的较深的lca一定为方点,并且方点与w直接相连,这样就可以满足了
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn=2e5+5;
int n,m,q,cnt;
vector <int> G[maxn],T[maxn];
int dfn[maxn],st[maxn],low[maxn],top;
int fa[maxn][21];
void tarjan(int u)
{
low[u]=dfn[u]=++dfn[0],st[++top]=u;
for(auto to:G[u])
{
if(!dfn[to])
{
tarjan(to);
low[u]=min(low[u],low[to]);
if(low[to]>=dfn[u])
{
++cnt;
// cerr<<cnt<<" "<<u<<" "<<to<<endl;
T[cnt].push_back(u);
T[u].push_back(cnt);
T[cnt].push_back(to);
T[to].push_back(cnt);
while(st[top]!=to)
{
int v=st[top--];
T[cnt].push_back(v);
T[v].push_back(cnt);
// cerr<<cnt<<" "<<v<<endl;
}
top--;
}
}
else low[u]=min(low[u],dfn[to]);
}
}
int dep[maxn];
void dfs(int u,int ff)
{
// cerr<<u<<endl;
fa[u][0]=ff; dep[u]=dep[ff]+1;
for(int i=1;i<=20;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
for(int to:T[u])
{
if(to==ff) continue;
dfs(to,u);
}
}
int lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
for(int i=20;i>=0;i--)
if(dep[fa[u][i]]>=dep[v])
u=fa[u][i];
if(u==v) return u;
for(int i=20;i>=0;i--)
if(fa[u][i]!=fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
cnt=n;
for(int i=1;i<=m;i++)
{
int x,y; scanf("%d%d",&x,&y);
G[x].push_back(y); G[y].push_back(x);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=cnt;i++) if(!fa[i][0]) dfs(i,0);
// for(int i=1;i<=cnt;i++) printf("%d ",dep[i]);
// printf("\n");
while(q--)
{
int u,v,w; scanf("%d%d%d",&u,&v,&w);
int la=lca(u,v),lb=lca(u,w),lc=lca(v,w);
int low_fa=la^lb^lc;
// cerr<<la<<" "<<lb<<" "<<lc<<endl;
if((!la) || (!lb) || (!lc))
{
printf("NO\n");
continue;
}
if(low_fa==w)
{
printf("YES\n");
continue;
}
if(low_fa>n && (fa[low_fa][0]==w || fa[w][0]==low_fa))
{
printf("YES\n");
continue;
}
printf("NO\n");
}
return 0;
}