首页 > 其他分享 >bitset 求解高维偏序

bitset 求解高维偏序

时间:2023-09-22 21:56:42浏览次数:130  
标签:偏序 ch 5005 int bitset 一维 mathcal 高维

菜,题简单,trick 蠢,求别骂。

记录今天做题的时候遇到的一个小 trick。

先看一道题:P3810 【模板】三维偏序(陌上花开)

平凡的三维偏序板子,相信大家都会用 CDQ/树套树/K-D tree 之类的优秀做法秒了吧!

然后看这个题:求五维偏序,\(n\le 3\times 10^4\),保证每一维这 \(n\) 个数都是 \(n\) 的排列。

我会套三层 CDQ 做到 \(\mathcal{O}(n\log^4n)\)!我还会 K-D tree 做到 \(\mathcal{O}(n^{\frac{7}{4}})\)!

然后看这个题:CF1826E. Walk the Runway

题意有点复杂,但是就是需要求 \(m\) 维偏序,\(m\le 500\),\(n\le 5000\),保证每一维都 \(\le n\)。

显然 CDQ 并不可取,如果直接暴力也是 \(\mathcal{O}(n^2m)\) 的,K-D tree 应该也不行(我不会)。怎么办?这里介绍一种使用 bitset 的简单做法。

有一个 \(n\times n\) 的矩阵 \(A\),\(A_{i,j}\) 为 1 表示 \(j\) 每一维都严格小于 \(i\)。枚举每一维 \(j\),排一遍序可以求出在这一维上严格小于第 \(i\) 个物品的集合,记为 \(S_{i,j}\)。显然 \(A_{i,j}\) 为 1 当且仅当 \(\forall k\in[1,m]\) 都有 \(j\in S_{i,k}\),而这个过程其实就是 bitset 求并。于是我们就做到了时间复杂度 \(\mathcal{O}(mn\log n+\dfrac{mn^2}{w})\),空间复杂度 \(\mathcal{O}(\dfrac{n^2}{w})\) 求 \(m\) 维偏序。

还可以优化吗?

考虑这道题:\(m\) 维偏序,\(n\le 5\times 10^4\),保证每一维这 \(n\) 个数都是 \(n\) 的排列,空间 64MB

空间爆了,怎么办?考虑分块优化空间。我们对于每一维进行值域上的分块,块长 \(b=\sqrt{n}\)。定义 \(f_{i,j}\) 表示第 \(i\) 维,这一维的值落在值域上 \([1,j\times b]\) 这一区间的点集,\(g_{i,j}\) 表示第 \(i\) 维值为 \(j\) 的点。显然这个可以 \(\mathcal{O}(mn\sqrt{n})\) 预处理。询问的时候依旧是整块取现成,暴力遍历散块。

这样做的话时间复杂度依旧是 \(\mathcal{O}(mn\sqrt{n}+\dfrac{mn^2}{w})\),但是空间优化到了 \(\mathcal{O}(\dfrac{mn\sqrt{n}}{w})\)(注意这道题可以这样做是因为保证每一维这 \(n\) 个数都是 \(n\) 的排列,如果只是像上一道题一样保证 \(\le n\) 则复杂度并不正确)。

附一个 CF1826E 的代码。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll inf=1e18;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
struct edge{
	int v,nxt;
}e[25000005];
int tot,head[5005],deg[5005];
void add(int u,int v){
	e[++tot]=(edge){v,head[u]},head[u]=tot,deg[v]++;
}
int n,m,b[5005],p[5005];ll a[5005],f[5005];
int cmp(int x,int y){
	return b[x]<b[y];
}
bitset<5005>res[5005];
void solve(){
	m=read(),n=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(i!=j)res[i][j]=1;
	for(int j=1;j<=m;j++){
		for(int i=1;i<=n;i++)b[i]=read(),p[i]=i;
		sort(p+1,p+n+1,cmp);bitset<5005>tmp;
		for(int i=1;i<=n;i++){
			int pos=i;while(pos<=n&&b[p[pos]]==b[p[i]])res[p[pos]]&=tmp,pos++;
			pos--;for(int k=i;k<=pos;k++)tmp[p[k]]=1;
			i=pos;
		}
	} 
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(res[i][j])add(i,j);
	queue<int>q;for(int i=1;i<=n;i++)if(!deg[i])q.push(i),f[i]=a[i];
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].v;f[v]=max(f[v],f[u]+a[v]);
			if((--deg[v])==0)q.push(v);
		}
	}
	ll ans=0;
	for(int i=1;i<=n;i++)ans=max(ans,f[i]);
	printf("%lld\n",ans);
}
signed main(){
	int T=1;
	while(T--){
		solve();
	}
	return 0;
}

reference:几道很Interesting的偏序问题 - yybbitset 求解高维偏序

标签:偏序,ch,5005,int,bitset,一维,mathcal,高维
From: https://www.cnblogs.com/xx019/p/17723344.html

相关文章

  • 高维前缀和
    考虑高维前缀和,可以把每一维前缀和比如:三维前缀和for(i=1;i<=a;i++) for(j=1;j<=b;j++) for(k=1;k<=c;k++) f[i][j][k]+=f[i-1][j][k];for(i=1;i<=a;i++) for(j=1;j<=b;j++) for(k=1;k<=c;k++) f[i][j][k]+=f[i][j-1][k];for(i=1;i<=a;i++)......
  • D. Searchlights 思维 偏序
     Problem-D-Codeforces 题意:分别给你一个n个pair<a,b>和m个pair<c,d>,问最少操作数,可以使得对于所有的<a,b>,对于任意的<c,d>,都有(a>c)或(b>d)。两个条件满足其一即可。操作的定义是,在一次操作中,你可以选a或b,然后对于所有的你选定的,都加1解法:对于每一个m,我们遍历n来求......
  • 【学习笔记】【自学】三维偏序 (CDQ)
    [P3810【模板】三维偏序(陌上花开)](https://www.luogu.com.cn/problem/P3810)题目描述:有$n$个元素,第$i$个元素有$a_i,b_i,c_i$三个属性,设$f(i)$表示满足$a_j\leqa_i$且$b_j\leqb_i$且$c_j\leqc_i$且$j\nei$的$j$的数量。对于$d\in......
  • STL——bitset的使用方法
    bitset介绍类似\(bool\)数组一样的东西,储存的是二进制,但是每一位只占\(1bit\),可以优化你算法的时间和空间复杂度。储存开一个bitset为:bitset<100>bs;最左边为最低位(即第\(0\)位),最右边为最高位。在初始化的时候,是从最低位开始储存。初始化有两种初始化整数bitse......
  • bitset 优化莫队
    题目传送门:Ynoi跳进兔子洞好题!我们观察题目,发现题目让我们求的可以写成:\[(r_1-l_1+1)+(r_2-l_2+1)+(r_3-l_3+1)-3\timessize\]其中:\(size\)是三段中公共颜色的个数问题转移成求三段公共颜色的个数。考虑使用莫队,然后在转换左右边界的时候使用数组记录每个颜色出现几次,然后......
  • S2 二,三维偏序
    二维偏序Q:给定N个有序对\((a,b)\),求对于每个\((a,b)\),满足\(a_0<a\)且\(b_0<b\)的有序对\((a_0,b_0)\)有多少个经典的逆序对问题,可以考虑用树状数组解决,先按照第一维排序,然后离散化在第一维已经处理的情况下去边处理第二维边记录。1.CF1311FMovingPoints不难......
  • H. Needle[FFT]或bitset
    Problem-H-Codeforces题意是给三面墙(简化为一条轴),然后给墙上的洞(简化成点),问多少直线可以从第一面墙穿出第三面墙。要使三点共线,那么(b-a)=(c-b)即(a+c)=2*b由于n是1e5所以O(n2)会超时。有两种做法1.本题的任意两数相加的步骤类似多项式乘法,我们把a,c看成两个多项式的系......
  • Codeforces Round 889 (Div. 1) B. Earn or Unlock(dp,bitset)
    题目链接:https://codeforces.com/problemset/problem/1854/B 题目大致题意: 有n张卡牌从上到下堆叠,每张卡片有锁或不锁俩种状态,一开始第一张是不锁的;对最上面的卡牌,如果他是不锁的状态,那么可以进行俩种操作:1:从上到下,将v张被锁的卡牌解锁;2:获取v点能量现在求能获得的最大的......
  • bitset优化01可行背包
    例题传送门:『STA-R3』Aulvwc先讲bitset用法:1,基础下标:\(5~4~3~2~1~0\)数字:\(0~0~0~0~1~0\)\(bitset\)<\(n\)>\(s\)表示一个\(n\)位的二进制数,空间复杂度:\(O(\frac{n}{32})\),可见其非常优秀因为其跟二进制有关,所以可以使用\(\&,|,\land\)对两个位数相同的\(bitset\)执行按......
  • 【学习笔记】二维偏序
    看着名字挺高级的就来学一下awa二维偏序是解决这样子的问题:有\(n\)个点,每一个点都有两个属性\(a,b\),且满足\[\left\{\begin{aligned}&i<j\\&a_i\lea_j\\&b_i\leb_j\end{aligned}\right.\]然后去求一些奇奇怪怪的问题解法是离散化后排序然后用两个树状数组来维护......