[Java] SPOJ Sumfour o.a. NZEC

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • noakes
  • Registratie: Juli 2012
  • Laatst online: 07-10-2022
Voor degenen die het niet weten. SPOJ is een online judge system for programming problems. Ik ben nu al een tijd bezig met het volgende probleem: SUMFOUR.
The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) belongs to A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n

Input

The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 2^28 ) that belong respectively to A, B, C and D .

Output should be printed on a single line.
Mijn aanpak is als volgt:
  • Lees de input in (respectievelijk array a, b, c en d van alle vier lengte n)
  • Vul array AB (lengte n^2) met alle mogelijke optellingen van a X b
  • Vul array CD (lengte n^2) me de negatie van alle mogelijke optellingen van c X d
  • Sorteer AB en CD met behulp van Arrays.sort()
  • Zie verder onderstaande code:
code:
1
2
3
4
5
6
7
8
9
idxAB = idxCD = result = 0
while (idxAB <AB.length-1 && idxCD <CD.length-1)
    int value = max(AB[idxAB], CD[idxCD])
    bepaal in AB en CD het aantal element (nAB en nCD) in de equal range voor waarde value.
    bepaal ook nieuwe idxAB en idxCD
    (index van de eerste waarde v in respectievelijk AB en CD waarvoor geldt v>value)
    result += nAB * nCD
    value = max(AB[idxAB], CD[idxCD])
return result


Het vinden van de equal range gaat op dit moment door het lineair doorlopen van de arrays (index in beide arrays worden dus bijgehouden). Ik deed dit eerst door recursief binary search toe te passen, maar lineair de lijst doorlopen blijkt in de meeste gevallen sneller te zijn (zeker wanneer er in AB en CD veel waarden voorkomen met relatief kleine equal ranges). De equal_range functie die je in C++ standaard beschikbaar hebt, heb ik in die vorm niet kunnen vinden voor Java.

Ik maak de a, b, c, d, AB en CD arrays static, zodat ze niet bij elke test opnieuw local worden aangemaakt.

Mijn eerste probleem dat ik krijg bij de eerste opzet is dat ik een NZEC krijg. Via het try/catchen van verschillende Throwables en Exceptions ben ik erachter gekomen dat er een OutOfMemoryError optreedt. Deze treedt op wanneer ik AB en CD aanmaak met size 4000*4000. Maak ik ze aan met bijvoorbeeld 2250*2250 dan gaat het nog net goed. Echter kunnen de lijstjes a,b,c en d maximaal lengte 4000 krijgen. Dus heb ik voor AB en CD 4000*4000 nodig om alle summaties te kunnen opslaan (en te sorteren). Wellicht dat iemand hier een idee heeft hoe dit op te lossen.

Bij 2250*2250 krijg ik een TLE (time limit exceeded). Ik weet dat een dergelijke oplossing in C++ kan werken. In Java is deze opdracht sowieso lastiger (er zijn maar zes werkende oplossingen ingeleverd). Dit vind ik een uitdaging, maar optimalisatie is soms echt een huzarenstukje. Vandaar mede ook dit topic. Ik heb ook nog een Parser geschreven die sneller de input kan inlezen. Deze zal ik hieronder ook nog even posten. Mocht niet baten in ieder geval.

Zelf zat ik al te denken om eventueel deze hele opzet te verlaten en eerder richting een hashtable (eventueel BitSet) te denken. Echter bij een Hashtable zonder collission heb ik mijnsinzien al snel 2^29 plaatsen nodig.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
 
class Main {
 
        private static int[][] ABCD = new int[4000][4];
        private static int[] AB = new int[4000 * 4000];
        private static int[] CD = new int[4000 * 4000];
        private static int LENGTH, LENGTH_2;
 
        public static void main(String[] args) throws Exception {
                System.out.println(sumfour());
        }
 
        private static long sumfour() throws Exception {
                BufferedReader bin = new BufferedReader(
                                new InputStreamReader(System.in));
                LENGTH = Integer.parseInt(bin.readLine());
                LENGTH_2 = LENGTH * LENGTH;
                String[] stra;
                // read four lists into abcd[0] to abcd[3]
                for (int i = 0; i < LENGTH; i++) {
                        stra = bin.readLine().split(" ");
                        for (int j = 0; j < 4; j++) {
                                ABCD[i][j] = Integer.parseInt(stra[j]);
                        }
                }
                // compute sum(A[] X B[]) into AB[]
                // compute sum(C[] X D[]) into CD[]
                int counter = 0;
                for (int i = 0; i < LENGTH; i++) {
                        for (int j = 0; j < LENGTH; j++) {
                                AB[counter] = ABCD[i][0] + ABCD[j][1];
                                CD[counter++] = (-1) * (ABCD[i][2] + ABCD[j][3]);
                        }
                }
                // sort ab[] and cd[]
                Arrays.sort(AB, 0, LENGTH_2);
                Arrays.sort(CD, 0, LENGTH_2);
 
                long start = System.nanoTime();
 
                int idxAB = 0, idxCD = 0, countAB, countCD, value;
                long result = 0;
                int results[] = new int[2];
                // determine first value to look for in both arrays
                value = Math.max(AB[idxAB], CD[idxCD]);
                boolean isEndOfArray = false;
                while (true) {
                        // elements in equal range of value in AB plus index of first
                        // element larger than value
                        results = findRangeIdx(AB, idxAB, value);
                        isEndOfArray = results[1] == -1;
                        idxAB = results[1];
                        countAB = results[0];
                        // elements in equal range of value in CD plus index of first
                        // element larger than value
                        results = findRangeIdx(CD, idxCD, value);
                        if (!isEndOfArray)
                                isEndOfArray = results[1] == -1;
                        idxCD = results[1];
                        countCD = results[0];
                        result += (long) countAB * (long) countCD;
                        if (isEndOfArray)
                                break;
                        // determine value for next step
                        value = Math.max(AB[idxAB], CD[idxCD]);
                }
 
                long end = System.nanoTime();
                //System.out.println("Running time: " + (end - start));
                return result;
        }
 
        /**
         * @param arr
         *            sorted array to scan
         * @param idx
         *            start scan from this index
         * @param value
         *            check how many elements have this value
         * @return [0]number of elements in equal range [1]index of first element >
         *         value (-1 if no such element)
         */
        private static int[] findRangeIdx(int[] arr, int idx, int value) {
                int counter = 0;
                while (idx <= LENGTH_2 - 1 && arr[idx] < value)
                        idx++;
                while (idx <= LENGTH_2 - 1 && arr[idx] == value) {
                        idx++;
                        counter++;
                }
                int[] result = { counter, -1 };
                if (idx < LENGTH_2)
                        result[1] = idx;
                return result;
        }
}

//Hieronder nog de Parser voor snellere input
class SPOJParserX {

    final private int BUFFER_SIZE = 1 << 16;
    private BufferedInputStream bin;

    public SPOJParserX(InputStream in) {
        bin = new BufferedInputStream(in, BUFFER_SIZE);

    }

    public void close() throws IOException {
        if (bin != null) {
            bin.close();
        }
    }

    public int nextInt() throws Exception {
        int ret = 0;
        byte c = (byte) bin.read();
        while (c <= ' ') {
            c = (byte) bin.read();
        }
        boolean neg = (c == '-');
        if (neg) {
            c = (byte) bin.read();
        }
        do {
            ret = ret * 10 + c - '0';
            c = (byte) bin.read();
        } while (c > ' ');
        if (neg) {
            return -ret;
        } else {
            return ret;
        }
    }
}

[ Voor 41% gewijzigd door RobIII op 19-11-2012 16:37 ]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Je hoeft niet te linken naar externe code; we hebben gewoon code tags tags. Vandaag of morgen verdwijnt je "pastie" en is je topic waardeloos voor mensen die hier in de toekomst nog op stuiten.

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • noakes
  • Registratie: Juli 2012
  • Laatst online: 07-10-2022
RobIII schreef op maandag 19 november 2012 @ 16:37:
Je hoeft niet te linken naar externe code; we hebben gewoon code tags tags. Vandaag of morgen verdwijnt je "pastie" en is je topic waardeloos voor mensen die hier in de toekomst nog op stuiten.
True! Dacht alleen dat mijn post zo wel erg lang werd. Maar je hebt gelijk, beter zo!

Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Zou die C++ implementatie die bovenaan staat (0.17 sec en 3.8MB geheugen) iets weten wat wij niet weten?

[ Voor 193% gewijzigd door Herko_ter_Horst op 19-11-2012 22:40 ]

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • noakes
  • Registratie: Juli 2012
  • Laatst online: 07-10-2022
Herko_ter_Horst schreef op maandag 19 november 2012 @ 22:36:
Zou die C++ implementatie die bovenaan staat (0.17 sec en 3.8MB geheugen) iets weten wat wij niet weten?
Zeker! Mijn aanpak geeft een accepted in C++, maar zeker niet in zo'n korte duur en kleine memory footprint als de oplossing die jij aanhaalt. Het zou kunnen dat de geaccepteerde Java oplossingen allemaal gebruik maken van de "betere" aanpak.

Via een kleine test ben ik erachter gekomen dat SPOJ NZEC geeft voor twee arrays van size 4000^2 (bij arrays van size 2500^2 gaat het bijvoorbeeld wel goed):
Java:
1
2
3
4
5
6
7
8
9
10
11
12
class Main {
    
    private final static int SIZE = 4000;        
    private final static int SIZE_2 = SIZE * SIZE;
    private static int[] AB = new int[SIZE_2];
    private static int[] CD = new int[SIZE_2];
    
    public static void main(String[] args) throws Exception {
        AB[SIZE_2-1]=1;
        CD[SIZE_2-1]=1;     
    }
}

Kwam deze opmerking tegen op het forum van SPOJ:
As an aside, I have reason to believe that there are no tests with 4000 values for this problem (because people seem to talk about it in terms of using n^2-sized arrays of ints, one of which would basically fill your memory limit on SPOJ). It annoys me a little bit when the constraints in the problem "bluff" - when I uploaded MATSUM, I changed the constraints from 5000x5000 to 1024x1024 because that was the biggest test that actually existed, and I didn't want people who figured out how to do it right AND were smart enough to realize that it wouldn't work if N was 5000 to be penalized
bron (sowieso wel een aardige read).

Ik heb ook het vermoeden dat er geen testcase wordt opgevoerd met n=4000. Ik heb net zelf mijn code gerund met size 2500 en dan krijg ik een TLE (time limit exceeded). Met size 2499 krijg ik een NZEC (dan loopt het uit de array) en met size >3000 krijg ik NZEC ivm OutOfMemoryError. Het lijkt er dus op dat de grootste testcase een n heeft van 2500. Hierdoor heb ik het OutOfMemoryError probleem getackeld, aangezien ik wel twee arrays kan aanmaken met size 2500^2. Helaas is mijn algo dan nog steeds te langzaam (in deze Java implementatie).

[ Voor 81% gewijzigd door noakes op 20-11-2012 12:24 ]


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 00:21

Janoz

Moderator Devschuur®

!litemod

Hmm, leuke uitdaging. Ik ga eens een Java poging wagen denk ik aangezien ik nog wel een optimalisatie denk te weten...

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • noakes
  • Registratie: Juli 2012
  • Laatst online: 07-10-2022
Janoz schreef op dinsdag 20 november 2012 @ 13:33:
Hmm, leuke uitdaging. Ik ga eens een Java poging wagen denk ik aangezien ik nog wel een optimalisatie denk te weten...
Dank! Ben erg benieuwd naar je bevindingen.

De oplossing die ik nu heb is O(n^2 * (log(n^2))) = O (n^2 * (log(n))). Ik ga nu zelf ook eens kijken naar een HashTable oplossing (dit zou dan in O(n^2) moeten kunnen). Alleen 't verwerken van collissions is lastig zonder de memory footprint snel te laten stijgen.

Ook nog "to try": sorteer eerst de arrays AB en CD en daarna deze via de "merge sort union step" samenvoegen .

[ Voor 26% gewijzigd door noakes op 20-11-2012 13:54 ]


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 00:21

Janoz

Moderator Devschuur®

!litemod

Precies. Je hoeft niet alle specifieke optellingen bij te houden.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • noakes
  • Registratie: Juli 2012
  • Laatst online: 07-10-2022
Implementatie met standaard HashMap geeft, zoals verwacht, TLE (zou ook OutOfMemoryError geven als hij maar lang genoeg kon draaien):
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

class Main {

    private static int[][] ABCD = new int[4000][4];

    public static void main(String[] args) throws Exception {
        System.out.println(sumfour());
    }

    private static long sumfour() throws Exception {
        BufferedReader bin = null;
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();

        bin = new BufferedReader(new InputStreamReader(System.in));
        int LENGTH = Integer.parseInt(bin.readLine());
        String[] stra;

        for (int i = 0; i < LENGTH; i++) {
            stra = bin.readLine().split(" ");
            for (int j = 0; j < 4; j++) {
                ABCD[i][j] = Integer.parseInt(stra[j]);
            }
        }
        Integer key = null;
        //Put every sum (=key) of AxB in HashMap (value = number of occurrence of sum)
        for (int i = 0; i < LENGTH; i++) {
            for (int j = 0; j < LENGTH; j++) {
                key = ABCD[i][0] + ABCD[j][1];
                if (map.containsKey(key)) {
                    map.put(key, map.get(key) + 1);
                } else {
                    map.put(key, 1);
                }
            }
        }
        long result = 0;
                //Check for every possible negatation of sum of CxD how many occurrences there are in AB
        for (int i = 0; i < LENGTH; i++) {
            for (int j = 0; j < LENGTH; j++) {
                key = (-1) * (ABCD[i][2] + ABCD[j][3]);
                if (map.containsKey(key)) {
                    result += (long) map.get(key);
                }
            }
        }
        return result;
    }
}

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 00:21

Janoz

Moderator Devschuur®

!litemod

hmm, pas bij de 3e submit kom ik er achter dat hij hem sowieso Main.java noemt.....


...... En toen kreeg ik een time limit exceeded...

[ Voor 25% gewijzigd door Janoz op 20-11-2012 14:47 ]

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • noakes
  • Registratie: Juli 2012
  • Laatst online: 07-10-2022
Janoz schreef op dinsdag 20 november 2012 @ 14:43:
hmm, pas bij de 3e submit kom ik er achter dat hij hem sowieso Main.java noemt.....


...... En toen kreeg ik een time limit exceeded...
Welke aanpak heb je?

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 00:21

Janoz

Moderator Devschuur®

!litemod

Ik heb verschillende geprobeerd, maar het kwam allemaal neer op het gebruik van maps. De aanpak was vergelijkbaar met je initiele aanpak, maar dan niet alle combinaties bijhouden, maar van elk mogelijk antwoord het aantal bij houden.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • noakes
  • Registratie: Juli 2012
  • Laatst online: 07-10-2022
Inmiddels heb ik mijn aanpak nog verder geoptimaliseerd (inclusief Parser). Een testcase met n=2500 gevuld met allerlei random numbers m (-2^28<= m <= 2^28) levert in ongeveer 2,1s (AMD Athlon 64 3700+) het gewenste antwoord op. Simpele testcase (als bijvoorbeeld allemaal 0-en en n=2500) levert in minder dan 0,3s het gewenste antwoord. Helaas krijg ik nog steeds "time limit exceeded".

Ik heb daarnaast ook een eigen hash map geschreven. Deze maakt gebruik van open addressing en double hashing. Probleem hierbij werd al snel de load factor. Aangezien ik maar max een array kon aanmaken van omgeveer 2700^2 int's (anders OutOfMemoryError van de JVM) en ik daarin soms 2500^2 elementen moest plaatsen (load factor van ongeveer 0,85% is niet ideaal) werkte dit ook niet goed (te langzaam op grote inputs). Ik hoop dat nog iemand de uitdaging in dit probleem ziet en met me mee wil denken.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

class Main {

    private static final int S = 2500;
    private static final int[] A = new int[S];
    private static final int[] B = new int[S];
    private static final int[] C = new int[S];
    private static final int[] D = new int[S];
    private static final int[] AB = new int[S * S];
    private static final int[] CD = new int[S * S];
    private static int res[];
    private static int L, L2;
    private static long ret, start, end;
    private static final int[] r = { 0, -1 };

    public static void main(String[] args) throws Exception {
        sumfour();
    }

    private static void sumfour() throws Exception {
        processInput();     
        //start = System.nanoTime();
        // sort ab[] and cd[]
        Arrays.sort(AB, 0, L2);
        Arrays.sort(CD, 0, L2);
        int iAB = 0, iCD = 0, cAB, cCD, val;
        ret = 0;
        // determine first value to look for in both arrays
        val = Math.max(AB[iAB], CD[iCD]);
        boolean isEnd = false;
        while (true) {
            // elements in equal range of value in AB plus index of first
            // element larger than value
            res = findRangeIdx(AB, iAB, val);
            isEnd = res[1] == -1;
            //System.out.println(iAB);
            iAB = res[1];
            cAB = res[0];
            // elements in equal range of value in CD plus index of first
            // element larger than value
            res = findRangeIdx(CD, iCD, val);
            if (!isEnd)
                isEnd = res[1] == -1;
            iCD = res[1];
            cCD = res[0];
            ret += (long)cAB * (long)cCD;
            if (isEnd)
                break;
            // determine value for next step
            val = Math.max(AB[iAB], CD[iCD]);
        }
        end = System.nanoTime();
        System.out.printf("Running time: %d.%ds\n", (end-start)/1000000000,(end-start)%1000000000 );
        System.out.println(ret);
    }

    private static void processInput() throws Exception {
        Parser parser = new Parser(System.in);
        // StdIn parser = new StdIn(System.in);
        L = parser.nextInt();
        start=System.nanoTime();
        L2 = L * L;
        // read four lists into A,B,C and D
        for (int i = 0; i < L; i++) {
            A[i] = parser.nextInt();
            B[i] = parser.nextInt();
            C[i] = parser.nextInt();
            D[i] = parser.nextInt();
        }
        // compute sum(A X B) into AB[]
        // compute -1 * sum(C X D) into CD[]
        int counter = 0;
        for (int i = 0; i < L; i++) {
            for (int j = 0; j < L; j++) {
                AB[counter] = A[i] + B[j];
                CD[counter++] = -1 * (C[i] + D[j]);
            }
        }
    }

    /**
     * @param arr
     *            sorted array to scan
     * @param idx
     *            start scan from this index
     * @param val
     *            check how many elements have this value
     * @return r[0] number of elements in equal range 
     *         r[1] index of first element >
     *         value val (-1 if no such element)
     */
    private static int[] findRangeIdx(int[] arr, int idx, int val) {
        int counter = 0;
        while (idx < L2 && arr[idx] < val) {
            idx++;
        }
        while (idx < L2 && arr[idx] == val) {
            idx++;
            counter++;
        }
        r[0] = counter;
        r[1] = -1;
        if (idx < L2)
            r[1] = idx;
        return r;
    }

    private static class Parser {

        final private int BUFFER_SIZE = 1 << 16;
        private BufferedInputStream bin;

        public Parser(InputStream in) {
            bin = new BufferedInputStream(in, BUFFER_SIZE);

        }

        public void close() throws IOException {
            if (bin != null) {
                bin.close();
            }
        }

        public int nextInt() throws Exception {
            int ret = 0;
            byte c = (byte) bin.read();
            while (c <= ' ') {
                c = (byte) bin.read();
            }
            boolean neg = (c == '-');
            if (neg) {
                c = (byte) bin.read();
            }
            do {
                ret = ret * 10 + c - '0';
                c = (byte) bin.read();
            } while (c > ' ');
            if (neg) {
                return -ret;
            } else {
                return ret;
            }
        }
    }
}
 }


En de custom Hash Map:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class HashMapCustom {
    private final static int N = 2700;
    protected static int keys[][];
    protected static int TABLE_SIZE = N * N + 37;
    protected static int size;
    protected static final int FREE = (-1 << 31);

    public HashMapCustom() {
        keys = new int[TABLE_SIZE][2];
        for (int i = 0; i < TABLE_SIZE; i++)
            keys[i][0] = FREE;
    }

    public int getValue(int idx) {
        return keys[idx][1];
    }

    public boolean contains(int key) {
        return indexOfKey(key) >= 0;
    }

    public int idxOfKey(int key) {
        return indexOfKey(key);
    }

    public boolean add(int key) {
        boolean result = addInternal(key);
        if (result)
            size++;
        return result;
    }

    protected boolean addInternal(int key) {
        int position = indexOfKey(key);
        boolean added = false;
        if (position < 0) {
            position = -position - 1;
            added = true;
            keys[position][1] = 1;
        } else
            keys[position][1] = keys[position][1] + 1;
        keys[position][0] = key;
        return added;
    }

    private int indexOfKey(int key) {
        int keyAbs = Math.abs(key);
        int startPosition = keyAbs % TABLE_SIZE; // 1st function
        int step = 1 + (keyAbs % (TABLE_SIZE - 7)); // 2nd function
        while (keys[startPosition][0] != key && keys[startPosition][0] != FREE) {
            startPosition -= step;
            if (startPosition < 0)
                startPosition += TABLE_SIZE;
        }
        if (keys[startPosition][0] == FREE)
            return -startPosition - 1;
        return startPosition;
    }
}

  • Cobalt
  • Registratie: Januari 2004
  • Laatst online: 02-07 21:48
Het is wellicht niet de snelste oplossing, maar zou dit niet het goede resultaat moeten opleveren?
Op de voorbeeld input geeft het netjes 5 terug, maar SPOJ geeft wrong answer.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.io.BufferedReader;
import java.io.InputStreamReader;
import static java.lang.Integer.parseInt;
import java.util.Arrays;

public class Main {
   
    public static void main(String[] args) {
        int i,j,k=0;
        long r=0;
        BufferedReader b;
        String[] s;
        try {
            b = new BufferedReader(new InputStreamReader(System.in));
            int n = parseInt(b.readLine());
            final int[] cd = new int[n*n];
            n *= 4;
            final int[] x = new int[n];
            for (i=0;i<n;i=i+4) {
                s = b.readLine().split(" ");
                x[i] = parseInt(s[0]);
                x[i+1] = parseInt(s[1]);
                x[i+2] = parseInt(s[2]);
                x[i+3] = parseInt(s[3]);
            }
            b.close();
            b=null;
            for (i=2;i<n;i=i+4)
                for (j=3;j<n;j=j+4) {
                    cd[k] = x[i]+x[j];
                    k++;
                }
            Arrays.sort(cd);
            for (i=0;i<n;i=i+4)
                for (j=1;j<n;j=j+4)
                    if(Arrays.binarySearch(cd,-(x[i]+x[j])) >= 0)
                        r++;
            System.out.println(r);
        } catch (Exception ex){}
    }
}
Pagina: 1