【HIHOCODER 1513】 小Hi的烦恼 (BitSet)

描述


小Hi从小的一大兴趣爱好就是学习,但是他发现尽管他认真学习,依旧有学神考的比他好。
小Hi在高中期间参加了市里的期末考试,一共五门:语文、数学、英语、物理、化学。
成绩出来之后,小Hi发现有些同学,所有科目都考的比他好,他很烦恼。所以他想知道所有科目都比自己名次靠前的同学的人数。
为了方便,可以认为不存在两个人某一门名次是相同的。
其他同学们也想知道有多少人全面碾压了他们,所以你需要对所有人输出答案。
解题方法提示

输入


第一行,一个正整数N(N <= 30000),表示人数。
接下来N行,每行五个整数,分别表示五门课依次的排名。

输出


输出共N行,每行一个整数,表示答案。

样例输入

4
1 1 2 2 1
2 3 3 3 2
3 2 1 1 3
4 4 4 4 4

样例输出

0
1
0
3

题解


BitSet就是一个大二进制串,同时实现了二进制数的各种位运算,我们利用任意位上的值为0或1来标志集合中是否存在这个数,可以有效的节约空间,同时也方便了各种集合运算。
BitSet内部实现以每32位转化为32位整型,然后32位的运算变为一次位运算,这样可以把整体\(O(n)\)的集合运算转化为\(O(n/32)\)
链接:BitSet常用方法
排名肯定是连续的,对于每一科排名,从前到后累计一下之前是那些人,最后在对第i个人每一科排名之前的人集合求一个交集。

Java版

import java.io.*;
import java.util.*;

public class Main {
	static final int N=30005;
	static final int inf=0x3f3f3f3f;
    static BitSet vis[][]=new BitSet[N][5];
    static BitSet a[]=new BitSet[N];
    static int id[][]=new int[N][5];
    static int x[][]=new int[N][5];
	public static void main(String[] args) {         
        InputStream sys=System.in;
        InputReader in=new InputReader(sys);
        PrintWriter out=new PrintWriter(System.out);
        int n=in.nextInt();
        for(int i=0;i<n;i++) {
        	for(int j=0;j<5;j++) {
        		x[i][j]=in.nextInt();
                id[x[i][j]][j]=i;
                vis[i][j]=new BitSet();
        	}
        	a[i]=new BitSet();
        	a[i].set(i,true);
        }
        for(int j=0;j<5;j++) {
        	vis[n][j]=new BitSet();
        }
        for(int i=1;i<=n;i++) {
        	for(int j=0;j<5;j++) {
        		vis[i][j]=(BitSet) vis[i-1][j].clone();
        		if(i<n) vis[i][j].set(id[i][j],true);
        	}
        }
        BitSet ans=new BitSet();
        for(int i=0;i<n;i++) {
        	ans=(BitSet) vis[x[i][0]][0].clone();
        	for(int j=1;j<5;j++) {
        		ans.and(vis[x[i][j]][j]);
        	}
            ans.andNot(a[i]);
        	out.println(ans.cardinality());
        }
        out.flush();
    }
	static class InputReader {
		public BufferedReader reader;
		public StringTokenizer tokenizer;
        
		public InputReader(InputStream stream) {
			reader = new BufferedReader(new InputStreamReader(stream), 32768);
			tokenizer = null;
		}

		public String next() {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					tokenizer = new StringTokenizer(reader.readLine());
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}
		
		public long nextLong() {
			return Long.parseLong(next());
		}
		
		public double nextDouble() {
			return Double.parseDouble(next());
		}
	}
}

C++版

#include <bitset>
#include <queue>
#include <cmath>
#include <cstdio>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ll long long
#define inf 1000000000
#define PI acos(-1)
#define REP(i,x,n) for(int i=x;i<=n;i++)
#define DEP(i,n,x) for(int i=n;i>=x;i--)
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void Out(ll a){
    if(a<0) putchar('-'),a=-a;
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=30005;
int x[N][5],id[N][5];
bitset<N> vis[N][5],a[N];
bitset<N> ans;
int main(){
    int n=read();
    for(int i=0;i<n;i++) {
        for(int j=0;j<5;j++) {
            x[i][j]=read();
            id[x[i][j]][j]=i;
        }
        a[i].set();
        a[i][i]=false;
    }
    for(int i=1;i<=n;i++) {
        for(int j=0;j<5;j++) {
            vis[i][j]=vis[i-1][j];
            if(i<n) vis[i][j].set(id[i][j],true);
        }
    }
    for(int i=0;i<n;i++) {
        ans=vis[x[i][0]][0];
        for(int j=1;j<5;j++) {
            ans&=vis[x[i][j]][j];
        }
        ans&=a[i];
        Out(ans.count());
        puts("");
    }
    return 0;
}
posted @ 2017-08-16 10:16  江南何采莲  阅读(181)  评论(0编辑  收藏  举报