题解 CF878D 【Magic Breeding】
给定
本题最有意思也是最难理解的是如何压缩状态量。首先显然每一个位置上的数是独立的,但是我们又不能直接独立考虑:因为这样你至少需要做
我们把视角放到某一位上,这样每一次都生成的是一个元素
接下来我们考虑 and 操作建立联系。
现在我们考虑询问,我们先给出流程,然后再证明它的正确性:我们把
下面来证明这样为什么是对的:
- 首先如果
f(x,s)=1 即无论a 怎么取都成立,那么对于a 给定的特殊情况也一定成立,也就是ans\geqslant a_i 。 - 如果
ans>a_i ,也就是说对于我们加入过程的某个前缀a_{b_k}\rightarrow a_{b_t} ,假设该前缀对应的集合是s' ,则f(x,s')=0 ,但是在这组a 的情况下有a_x\geqslant \min_{j\in s'}(a_j)=a_t 。
我们注意到如果存在一组a' 使得a'_x< \min_{j\in s'}(a'_j) ,那展开a'_x 的生成过程,一定有一步\min 操作使得两个元素一个属于s' ,另一个不属于s' ,之后的操作都只在s' 的补集中进行,而在当前的a 下,s' 中的a 是整个序列最大的一部分,所以这个\min 操作也会使得a_x 对应的下标变为s' 补集中的元素,与条件不符。
感性理解就是由于我们是从大到小枚举的,那么这个限制已经是所有限制中最紧的那个,如果最紧的限制满足,则其它的也一定满足。
所以这样一定有 bitset 加速,所以总复杂度
代码:
#include<bits/stdc++.h>
using namespace std;
bitset<4096>f[100020];
int a[13][100005],b[100005][13],now;
bool cmp(int x,int y){return a[x][now]==a[y][now]?x>y:a[x][now]>a[y][now];}
int main()
{
int n,q,k,cnt,op,x,y;
scanf("%d%d%d",&n,&k,&q);cnt=k;
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]),b[j][i]=i;
for(int i=1;i<=n;i++)now=i,sort(b[i]+1,b[i]+k+1,cmp);
for(int i=1;i<=k;i++)
for(int j=0;j<(1<<k);j++)
if(j&(1<<(i-1)))f[i][j]=1;
while(q--)
{
scanf("%d%d%d",&op,&x,&y);
if(op==1)cnt++,f[cnt]=f[x]|f[y];
else if(op==2)cnt++,f[cnt]=f[x]&f[y];
else
for(int i=1,t=0;i<=k;i++)
{
t|=(1<<(b[y][i]-1));
if(f[x][t]){printf("%d\n",a[b[y][i]][y]);break;}
}
}
return 0;
}