对于一个叫做foo的bitset:
foo.size() 返回大小(位数)
foo.count() 返回1的个数
foo.any() 返回是否有1
foo.none() 返回是否没有1
foo.set() 全都变成1
foo.set(p) 将第p + 1位变成1
foo.set(p, x) 将第p + 1位变成x
foo.reset() 全都变成0
foo.reset(p) 将第p + 1位变成0
foo.flip() 全都取反
foo.flip(p) 将第p + 1位取反
foo.to_ulong() 返回它转换为unsigned long的结果,如果超出范围则报错
foo.to_ullong() 返回它转换为unsigned long long的结果,如果超出范围则报错
foo.to_string() 返回它转换为string的结果
题目大意:求对于每个人来说,5门功课的名次都比他靠前的人数。
由提示中,我们就知道需要用bitset用解这题,(否则的话五维偏序得CDQ分治和数据结构套来套去)。主要思路就是如果我们知道单独每个科目名次靠前的集合,那么就是求5个集合的交集,但这个求交集上如果是用暴力的方法很明显会超时,这时候就需要运用到bitset了,其实c++/Java中的一种数据结构类似于数组,但可以直接对其做位运算。这样我们知道每个人的每门功课排第几,那么我们也可以知道每门功课排第几是谁。这样的话,bitset比当前名次靠前的人,如100100,就表示这么功课比当前名次靠前的有第0个人,和第3个人(我习惯从0开始),类似状压的思想。
1 #include<cstdio> 2 #include<bitset> 3 using namespace std; 4 const int N=30118; 5 int a[N][6],b[6][N]; 6 //a[i][j]第i个人第j门功课排第几, b[i][j]第i功课排第j的是谁 7 bitset<N> c[6][N],ans;//c[i][j]第i门功课排第j的人,名次比他高的有谁 8 int main() 9 { 10 int n; 11 while(~scanf("%d",&n)) 12 { 13 for(int i=0;i<n;i++) 14 for(int j=0;j<5;j++) 15 { 16 scanf("%d",&a[i][j]); 17 a[i][j]--;//因为我是从0开始的,所以这里-- 18 b[j][a[i][j]]=i; 19 c[j][i].reset(); 20 } 21 for(int i=0;i<5;i++) 22 for(int j=1;j<n;j++) 23 { 24 c[i][j]=c[i][j-1]; 25 c[i][j].set(b[i][j-1]); 26 } 27 for(int i=0;i<n;i++) 28 { 29 ans=c[0][a[i][0]]; 30 for(int j=1;j<5;j++) 31 ans&=c[j][a[i][j]]; 32 printf("%d ",ans.count()); 33 } 34 } 35 return 0; 36 }
更多的见nimphy的【整理】STL中的bitset(二进制华丽解决假五维偏序题)