public static Pair<Integer, Integer> linearCongruenceSystem(final int count,
            final List<Integer> aInList, final List<Integer> bInList, final List<Integer> nInList) {
        
        positiveCheck(count);
        listCheck(count, aInList);
        listCheck(count, bInList);
        listCheck(count, nInList);
        final List<Integer> aList = new ArrayList<>(aInList);
        final List<Integer> bList = new ArrayList<>(bInList);
        final List<Integer> nList = new ArrayList<>(nInList);
        for (int i = 0; i < count; ++i) {
            final int ai = aList.get(i);
            final int bi = bList.get(i);
            final int ni = nList.get(i);
            positiveCheck(ni);
            aList.set(i, normalizeIntModulo(ai, ni));
            bList.set(i, normalizeIntModulo(bi, ni));
        }
        
        final Pair<Integer, Integer> solution = new Pair<>();
        for (int i = 0; i < count; ++i) {
            final Pair<Integer, Integer> partial =
                    linearCongruence(aList.get(i), bList.get(i), nList.get(i));
            if (partial.isEmpty()) // no solutions for whole system
                return new Pair<>(); 
            if (partial.equals(new Pair<>(0, 1))) { // infinite solutions for congruence 'i'
                if ((solution.isEmpty()) && (Utils.lastForCycle(i, count)))
                    return new Pair<>(0, 1);
                
                continue;
            }
            
            // xi == partialX + partialM * k
            final int partialX = partial.getFirst();
            final int partialM = partial.getSecond();
            if (solution.isEmpty()) {
                solution.setFirst(partialX);
                solution.setSecond(partialM);
            } else {
                solution.setFirst(solution.getFirst() + solution.getSecond() * partialX);
                solution.setSecond(solution.getSecond() * partialM);
            }
            
            if (!Utils.lastForCycle(i, count)) {
                bList.set(i+1, bList.get(i+1) - (aList.get(i+1) * solution.getFirst()));
                aList.set(i+1, aList.get(i+1) * solution.getSecond());
            }
        }
        return solution;
    }