比赛的时候只做了两个题,太菜了,实际上补的时候并没有感觉很难。
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);
}