计蒜课周赛题解(计蒜课第四场)

比赛的时候只做了两个题,太菜了,实际上补的时候并没有感觉很难。
A. 从零开始的神棍之路
深搜就完事了。

#include<bits/stdc++.h>
using namespace std;

int p1,ret1,ret2;
int vis[30];
int dfs(int d)
{
    if(d==1)
    {
        p1=ret1=ret2=0;
        for(int i=1;i<=27;i++)if(vis[i]>=2)
        {
            vis[i]-=2;
            if(i%9==0||i%9==1)p1++;
            if(dfs(2))return 1;
            if(i%9==0||i%9==1)p1--;
            vis[i]+=2;
        }
        return 0;
    }
    else if(d==6)
    {
        if(p1==0||p1==5)return 1;
        if(ret1==4||ret2==4)return 1;
        return 0;
    }
    else
    {
        for(int i=1;i<=27;i++)if(vis[i])
        {
            if(vis[i]>=3)
            {
                vis[i]-=3;
                if(i%9==0||i%9==1)p1++;
                ret2++;
                if(dfs(d+1))return 1;
                ret2--;
                vis[i]+=3;
                if(i%9==0||i%9==1)p1--;
            }
            if(i%9!=0&&i%9!=8&&vis[i]&&vis[i+1]&&vis[i+2])
            {
                vis[i]--;vis[i+1]--;vis[i+2]--;
                ret1++;
                if(i%9==1||i%9==7)p1++;
                if(dfs(d+1))return 1;
                ret1--;
                if(i%9==1||i%9==7)p1--;
                vis[i]++,vis[i+1]++,vis[i+2]++;
            }
        }
        return 0;
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(vis,0,sizeof(vis));
        int tmp;
        for(int i=1;i<=14;i++)
            scanf("%d",&tmp),vis[tmp]++;
        int res=0;
        for(int i=1;i<=27;i++)
            if(vis[i]==2)res++;
        if(res==7){puts("1");continue;}
        printf("%d\n",dfs(1));
    }
    return 0;
}

B. Zeratul与Xor
建一个01字典树,异或可以在查询的时候再异或。关键是建字典树的时候得递归建,这样父节点就可以知道它下面有多少个数。

#include<bits/stdc++.h>
using namespace std;

struct node
{
    int s[2];
    int times;
    int cnt;
    //node(int _times):l(_l),r(_r),times(_times){}
    node()
    {
        memset(s,-1,sizeof(s));
        times=cnt=0;
    }
}nodes[32*100005];

int tot;
int root;

int newnode()
{
    tot++;
    return tot;
}

void insert(int rt,int num,int d)
{
    if(d==-1)
    {
        nodes[rt].times++;
        nodes[rt].cnt=nodes[rt].times;
        return;
    }
    int go=(num>>d)&1;
    if(nodes[rt].s[go]==-1)
        nodes[rt].s[go]=newnode();
    insert(nodes[rt].s[go],num,d-1);
    nodes[rt].cnt=nodes[nodes[rt].s[0]].cnt+nodes[nodes[rt].s[1]].cnt;
}
int ans,num;
int nowxor;

void dfs(int rt,int nownum,int d)
{
    if(ans!=-1)return;
    if(nodes[rt].times)
    {
        ans=nownum;
        return;
    }
    int go=(nowxor>>d)&1;
    //bool flag=1;
    //if(num>nodes[nodes[rt].s[go]].cnt)flag=0;
    if(nodes[rt].s[go]!=-1&&num<=nodes[nodes[rt].s[go]].cnt)
            dfs(nodes[rt].s[go],nownum*2+go,d-1);
    else
        {
            if(nodes[rt].s[go]!=-1)num-=nodes[nodes[rt].s[go]].cnt;
            dfs(nodes[rt].s[(go^1)],nownum*2+(go^1),d-1);
        }

}

int main()
{
    int n,q;
    scanf("%d %d",&n,&q);
    root=newnode();
    int a;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a);
        insert(1,a,30);
    }
    int opt,x;
    nowxor=0;
    for(int i=1;i<=q;i++)
    {
        scanf("%d %d",&opt,&x);
        if(opt==1)
            nowxor=nowxor^x;
        else if(opt==2)
        {
            x=x^nowxor;
            insert(1,x,30);
        }
        else
        {
            ans=-1;
            num=x;
            dfs(1,0,30);
            printf("%d\n",(ans^nowxor));
        }
    }
    return 0;
}

M. Big brother said the calculation
这个特别有意思,我们可以二分答案,然后比mid大的数我们将它看成1,比它小的看成0,然后用线段树来维护操作。看操作完了询问的第k个数是1还是0,我们就知道答案比当前的数大还是小了。
线段树的操作也就是区间求和,区间修改。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
tuple<int,int,int>change[maxn];
int a[maxn];

struct node
{
    int l,r;
    int num,lazy;
    int sum;
    node(int _l,int _r,int _num,int _sum,int _lazy):l(_l),r(_r),num(_num),sum(_sum),lazy(_lazy){}
    node(){}
}nodes[maxn<<2];
#define ls l,mid,rt<<1
#define rs mid+1,r,rt<<1|1
int b[maxn];

void pushup(int rt)
{
    nodes[rt].sum=nodes[rt<<1].sum+nodes[rt<<1|1].sum;
}

void build(int l,int r,int rt)
{
    if(l==r)
    {
        nodes[rt]=node(l,r,b[l],b[l],0);
        return;
    }
    nodes[rt]=node(l,r,0,0,0);
    int mid=l+r>>1;
    build(ls);
    build(rs);
    pushup(rt);
}
int n,q,k;

void pushdown(int rt)
{
    if(nodes[rt].lazy)
    {
        nodes[rt<<1].num=nodes[rt].num;
        nodes[rt<<1|1].num=nodes[rt].num;
        nodes[rt<<1].sum=(nodes[rt<<1].r-nodes[rt<<1].l+1)*nodes[rt<<1].num;
        nodes[rt<<1|1].sum=(nodes[rt<<1|1].r-nodes[rt<<1|1].l+1)*nodes[rt<<1|1].num;
        nodes[rt<<1].lazy=nodes[rt].lazy;
        nodes[rt<<1|1].lazy=nodes[rt].lazy;
        nodes[rt].lazy=0;
    }
}

int query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
        return nodes[rt].sum;
    pushdown(rt);
    int mid=l+r>>1;
    int res=0;
    if(L<=mid)
        res+=query(L,R,ls);
    if(R>mid)
        res+=query(L,R,rs);
    return res;
}

void update(int L,int R,int C,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        nodes[rt].num=C;
        nodes[rt].lazy=1;
        nodes[rt].sum=(r-l+1)*C;
        return;
    }
    pushdown(rt);
    int mid=l+r>>1;
    if(L<=mid)
        update(L,R,C,ls);
    if(R>mid)
        update(L,R,C,rs);
    pushup(rt);
}

int check(int num)
{
    for(int i=1;i<=n;i++)
        if(a[i]>=num)
            b[i]=1;
        else b[i]=0;
    build(1,n,1);
    for(int i=1;i<=q;i++)
    {
        int l=get<0>(change[i]),r=get<1>(change[i]),t=get<2>(change[i]);
        int thsum=query(l,r,1,n,1);
        int len=r-l+1;
        if(t==0)
        {
            if(l<=l+len-thsum-1)
                update(l,l+len-thsum-1,0,1,n,1);
            if(l+len-thsum<=r)
                update(l+len-thsum,r,1,1,n,1);
        }
        else
        {
            if(l<=l+thsum-1)
                update(l,l+thsum-1,1,1,n,1);
            if(l+thsum<=r)
                update(l+thsum,r,0,1,n,1);
        }
    }
    return query(k,k,1,n,1);
}

int main()
{

    scanf("%d %d %d",&n,&q,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    int l,r,t;
    for(int i=1;i<=q;i++)
    {
        scanf("%d %d %d",&l,&r,&t);
        change[i]=make_tuple(l,r,t);
    }
    l=1,r=n;
    int ans;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(check(mid))
        {
            ans=mid;
            l=mid+1;
        }
        else
            r=mid-1;
    }
    printf("%d\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值