7.21训练总结

考场错误、经验:
今天的前几题,难度比较小,但是我罚时有点多,这个需要改进
当做到博弈论的题目时,忘记了sg函数的相关知识定义,导致一直卡住
然后看了GH没什么人做,所以也没有仔细思考,一直卡在博弈论的题目上
这点应该注意,一道题目确定做不出来就要及时放弃,去做其他的题目

sg函数要注意,还有 n ∗ m ≤ 1 e 5 n*m \le 1e5 nm1e5要注意较小值一定 < 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 nm1e5,可以得到 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值