[题解]CodeForces878 D - Magic Breeding
Posted scl123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[题解]CodeForces878 D - Magic Breeding相关的知识,希望对你有一定的参考价值。
题目描述
有(K)只神奇的生物,每一只有(n)个属性。Q次操作:
- ((1,x,y)):产生一只新的生物,每一个属性为(x)和(y)的该属性的最大值
- ((2,x,y)):产生一只新的生物,每一个属性为(x)和(y)的该属性的最小值
- ((3,x,y)):查询第(x)只生物的(y)属性
每一次新生物的编号为最小的没有被使用的正整数
(1leq K leq 12,1leq n,Qleq 10^5)
分析
感觉这题只可意会比较难讲清楚qwq
首先,每一只新生物的属性来自于最开始的(K)只生物,这非常显然
官方题解里面说的是只可能有(2^K)种情况,把每一种用一个(K)位二进制数来表示,第(i)位为(1)表示这种生物的每一个属性都小于等于第(i)种生物的对应属性。
我们对于每一种生物存一个(2^K)位的状态,记为 (f),表示这个生物的每一个属性为((((1)位上的情况)的这种属性)中最大的)。具体地:
假如我们要求第(x)个生物的第(y)种属性,那么我们按照y属性从大到小的顺序枚举每一种最开始的生物,并把它或到(mask)中,如果(x)生物的第(mask)位为1,那么答案就是当前生物的这个属性
int now=0;
rep(i,1,K){
now|=(1<<(id[y][i]-1));
if(f[x][now]==1){
printf("%d
",a[id[y][i]][y]);
return;
}
}
对于1操作:每一个属性只需要(leq)x的这个属性或(leq)y的这个属性,所以新的生物的状态就是(f[x]|f[y])
对于2操作:每一个属性都要(leq)x的这个属性且(leq)y的这个属性,新状态为(f[x])&(f[y])
算了还是毛估估吧
代码
#include<bits/stdc++.h>
#define rep(X,A,B) for(int X=A;X<=B;X++)
#define tep(X,A,B) for(int X=A;X>=B;X--)
#define LL long long
#define DB double
const int KK=15;
const int N=100015;
const int MX=1<<13;//!!!!!!!!!
using namespace std;
int n,K,Q,tot,hlp,maxn;
int a[KK][N],id[N][KK];
bitset<MX>f[N];
void READ(){
scanf("%d%d%d",&n,&K,&Q);
rep(i,1,K)rep(j,1,n)scanf("%d",&a[i][j]);
tot=K;
}
int cmp(int x,int y){
return a[x][hlp]>a[y][hlp];
}
void INIT(){
maxn=(1<<K)-1;
rep(i,1,K){
rep(num,0,maxn){
if(num&(1<<(i-1)))f[i][num]=1;
}
}
rep(i,1,n){
rep(j,1,K)id[i][j]=j;
hlp=i;
sort(id[i]+1,id[i]+K+1,cmp);
}
}
void SOLVE(){
int pd,x,y;
scanf("%d%d%d",&pd,&x,&y);
if(pd==1)f[++tot]=f[x]|f[y];
if(pd==2)f[++tot]=f[x]&f[y];
if(pd==3){
int now=0;
rep(i,1,K){
now|=(1<<(id[y][i]-1));
if(f[x][now]==1){
printf("%d
",a[id[y][i]][y]);
return;
}
}
}
}
int main(){
READ();
INIT();
while(Q--)SOLVE();
return 0;
}
以上是关于[题解]CodeForces878 D - Magic Breeding的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces878 A. Short Program
Codeforces878E. Numbers on the blackboard