CCF 15 csp authentication Problem 3 CIDR combined sequence (java 100 points)

Began searching solution to a problem is 90 points because of java are not familiar with, you learn a lot of things from the inside, indexOf, split, as well as approach to merger.

The last point can not be over, I started my way to optimize it.

Sorting solution to a problem that insertion sort, this is O (n * n * log (n)), I used to sort, can be reduced to O (n * log (n)).

In the process of merging, the solution to a problem when the method of using simulated remove operation, so that together would require O (n) scanning time is O (n * n) complexity.

It is optimized to O (n). For both merge, I have adopted the process of scanning the points required to stay the idea, so do not spend the extra time to list the elements that were removed from the inside, O (n) sweep over like. The second comparison because before the merger and also, I use the stack, each element is compared with the top of the stack and position to be compared, if you want to merge on the stack, to compare the new results on the inside, empty when put to stack the results, compare add an extra 1. This complexity and the number of comparisons achieve the same purpose.

Such complexity is the highest ranking when the need O (nlog (n)), should be able to live, but still 90 points. I was stuck for a long time.

But then the club xzq seniors told me the Scanner java is slow, like c ++ cin the same large amount of data needs to be optimized input and output. I went a bit input and output optimization methods, and finally passed. Very exciting ah, this is the whole network starting csp15-3 java achieve out of solution to a problem (Tacca self-Hi)!

Most begin to understand the idea of writing and blog, I find explanations https://blog.csdn.net/qq_36143109/article/details/88411854#commentBox

Learning blog acceleration input https://www.jianshu.com/p/1184545102c7

 


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


class prefix implements Comparable<prefix>{
	public int[] ip;
	public int len;
	public prefix(int[] ip,int len) {
		this.ip = ip;
		this.len = len;
	}
	public int compareTo(prefix x) {
		for(int i = 0; i < 4; i++) {
			if(this.ip[i] != x.ip[i])
				return this.ip[i] - x.ip[i];
		}
		return this.len - x.len;
	}
}
 

class Reader {
    static BufferedReader reader;
    static StringTokenizer tokenizer;

    /**
     * call this method to initialize reader for InputStream
     */
    static void init(InputStream input) {
        reader = new BufferedReader(
                new InputStreamReader(input));
        tokenizer = new StringTokenizer("");
    }

    /**
     * get next word
     */
    static String next() throws IOException {
        while (!tokenizer.hasMoreTokens()) {
            //TODO add check for eof if necessary
            tokenizer = new StringTokenizer(
                    reader.readLine());
        }
        return tokenizer.nextToken();
    }

    static int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    static double nextDouble() throws IOException {
        return Double.parseDouble(next());
    }
}

public class Main {
 
	public static void main(String[] args) throws IOException {
		
//		Scanner in = new Scanner(System.in);
		
//		int n = Integer.parseInt(in.nextLine());
		Reader.init(System.in);
		int n = Reader.nextInt();
		
		List<prefix> list = new ArrayList<prefix>(); 
		
		
		//读入并转换成prefix类
		for(int d = 0;d<n;d++) {
			
//			String ip = in.nextLine();
			String ip = Reader.next();
			//构建prefix对象
			int[] Ip = new int[4];
			int len = 0;   
			int index = ip.indexOf("/");
			if(index != -1) {
				String[] b =  ip.split("/");
				len = Integer.parseInt(b[1]);
				String str = b[0];
				if(str.indexOf(".") != -1) b = str.split("\\.");
				else b = new String[] {str};
				//同时处理了省略后缀型和标准型
				for(int i = 0; i < b.length; i++)  Ip[i] = Integer.parseInt(b[i]);
				for(int i = b.length; i<4 ;i++)  Ip[i] = 0;
			}else {//省略长度型
				String[] b =  new String[]{ip};
				if(ip.indexOf(".") != -1) b = ip.split("\\.");
				len = b.length * 8;
				for(int i = 0;i < b.length;i++)  Ip[i] = Integer.parseInt(b[i]);
				for(int i = b.length; i < 4; i++)  Ip[i] = 0;
			}
			prefix prefix = new prefix(Ip,len);
			list.add(prefix);
		}
		
		Collections.sort(list);
		
		List<prefix> list1 = new ArrayList<prefix>();
		
		//从小到大合并 从list找到合并后的元素放到list1里面
		int size = list.size() - 1;
		int min;
		int[] ip1, ip2;
		
		//k和k + 1匹配,能匹配则删掉k + 1,继续和新的k + 1匹配
		int k = 0, nxt;//nxt指向第一个不能和k合并的值
		while(k <= size) {
			list1.add(list.get(k));
			nxt = k + 1;
			if(nxt > size) break;
			while(nxt <= size) {
				min = Math.min(list.get(k).len, list.get(nxt).len);
				ip1 = and(list.get(k).ip,min);
				ip2 = and(list.get(nxt).ip,min);
				//取更小的长度min min之后的部分截掉变成0, 如果计算结果相同说明它们的匹配集相同
				if(cmp(ip1, ip2) == 0) 
					nxt++;
				else break;				
			}
			k = nxt;
		}
		
		
		list.clear();
		size = list1.size() - 1;
		for(int i = 0; i <= size; i++){
			list.add(list1.get(i));
		}

		//同级合并,永远从栈顶开始找
		Stack<prefix> list2 = new Stack<prefix>();
		size = list.size();
		int compare = 1;
		list2.push(list.get(0));
		while(compare < size) {
			prefix from = list2.pop();
			prefix get = can_combine2(from, list.get(compare));
			if(get == from) {
				list2.push(from);
				list2.push(list.get(compare));
				compare++;
			}
			else {
				list.set(compare, get);
				if(list2.empty()) {
					list2.push(list.get(compare));
					compare++;
				}
			}
		}
		
		size = list2.size();
		for(int i = 0; i < size; i++) list1.set(i, list2.pop());
		list.clear();
		for(int i = size - 1; i >= 0; i--) list.add(list1.get(i));
		
//		in.close();
			
		StringBuilder sb = new StringBuilder();
		for(prefix show:list) {
			sb.append(show.ip[0]+"."+show.ip[1]+
					"."+show.ip[2]+"."+show.ip[3]+"/"+show.len + "\n");
			
		}
		sb.append(" ");
		System.out.print(sb);
//		for(prefix show:list) {
//			System.out.println(show.ip[0]+"."+show.ip[1]+
//					"."+show.ip[2]+"."+show.ip[3]+"/"+show.len);
//		}
		
		
	}
	
	public static prefix can_combine2(prefix a, prefix b) {
		//如果不能合并,返回a
		if(a.len != b.len) return a;
		int len = a.len - 1;
		int[] ip1 = and(a.ip, len);
		int[] ip2 = and(b.ip, len);
		if(cmp(ip1, ip2) == 0) return new prefix(ip1, len);
		else return a;
	}
	
	public static int cmp(int[] x, int[] y) {
		for(int i = 0; i < 4; i++) {
			if(x[i] > y[i])
				return 1;
			if(x[i] < y[i])
				return -1;
		}
		return 0;
	}
	
	public static int cmp1(prefix a, prefix b) {
		//判断a是否比b大, a > b返回1, a < b返回-1,a == b返回0
		int[] x = a.ip;
		int[] y = b.ip;
		for(int i = 0;i < 4;i++) {
			if(x[i] > y[i])
				return 1;
			else if(x[i] < y[i])
				return -1;
		}
		if(a.len < b.len) return -1;
		else if(a.len == b.len) return 0;
		else return 1;
	}
	
	//获得一个前len位和p一样,后面为0的ip地址,用长度为4的数组表示
	public static int[] and(int[] p, int len) {
		int n = len / 8;
		int m = len % 8;
		int[] P = new int[4];
		for(int i = 0; i < n; i++) P[i] = p[i];
		//-1的二进制位全部是1,左移8-m位刚好使末尾8-m位是0
		if(n<4) P[n] = p[n] & (-1 << (8 - m));
		for(int i = n + 1; i < 4; i++) {
			P[i] = 0;
		}
		return P;
	}
}

 

Guess you like

Origin blog.csdn.net/xuzonghao/article/details/89339721