Problem:
Problem B: Matsuzaki Number

Matsuzaki 教授は，宇宙の真理を研究している科学者である．人生，宇宙，すべての答えは 42 であると言われているが，Matsuzaki 教授はこれだけでは宇宙の真理を解明するには不十分であると考えている．Matsuzaki 教授は，宇宙の真理は 2 つのパラメータからなる関数で表されると考えており，42 はその 1 つに過ぎないというのである．

Matsuzaki 教授の定義した関数 M(N, P) は，N より大きい素数を 2 つ選んで（同じ数を 2 つでも構わない）和をとることで得られる数の全体を，小さいほうから順番に並べたときに，P 番目に現れる数を表す．ここで，2 通り以上の和で表されるような数も存在するが，そういった数は和の組み合わせの数と同じ個数だけ並べられる．

例として N = 0 の場合を考えよう．このときは素数全体から 2 つを選んで和をとることになる．そういった和のうちで最小の数を考えると，同じ数を 2 回選ぶことも許されていることから，2 + 2 = 4 であることがわかる．すなわち M(0, 1) = 4 である．次に小さい数は 2 + 3 = 5 であるから M(0, 2) = 5 となる．同様にして考えると，和を並べたものは 4, 5, 6, 7, 8, 9, 10, 10, 12, 13, 14, 14, 16, ... のようになることがわかる．すなわち，たとえば M(0, 9) = 12 である．

同じようにして N = 10 の場合を考えると，このときは 10 より大きい素数 {11, 13, 17, 19, ...} から 2 つを選ぶことになり，得られる和を小さいほうから並べると 22, 24, 26, 28, 30, 30, 32, ... のようになる．

あなたの仕事は，N と P が与えられた時に M(N, P) を計算するプログラムを書くことである．

Input

入力は複数のデータセットからなる．データセットは 1 行であり，2 つの整数 N (0 ≤ N ≤ 100,000) と P (1 ≤ P ≤ 100) が 1 つの空白で区切られて与えられる．

入力の終わりは，空白で区切られた 2 つの -1 を含む 1 行で示される．

Output

各データセットに対して，M(N, P) の値を 1 行に出力せよ．出力に余計な空白や改行を含めてはならない．

Sample Input

0 55
0 1
0 2
0 3
10 1
10 2
10 3
10 4
10 5
10 6
11 1
11 2
11 3
100000 100
-1 -1

Output for the Sample Input

42
4
5
6
22
24
26
28
30
30
26
30
32
200274

Solution in C (judge verdict: Accepted)

#include <stdio.h>
#include <stdlib.h>

#define MAX_N 101000
#define SWAP( a, b ) do { int tmp; tmp = a; a = b; b = tmp; } while( 0 )

int isPrime[ MAX_N + 1 ] = { 0, 0, 1 };

void insertionSort( int *, int );
void quickSort( int *, int );
int median( int, int, int );

int main( void ) {
	int i, j, N, P, cnt, p[ 22 ], sum[ 253 ];

	for ( i = 3; i <= MAX_N; i += 2 )
		isPrime[ i ] = 1;

	for ( i = 3; i * i <= MAX_N; i += 2 )
		if ( isPrime[ i ] )
			for ( j = i * 2; j <= MAX_N; j += i )
				isPrime[ j ] = 0;

	for ( ; scanf( "%d %d", &N, &P ), N != -1; printf( "%d\n", sum[ P - 1 ] ) ) {
		cnt = 0;
		for ( i = N + 1; cnt < 22; i++ )
			if ( isPrime[ i ] )
				p[ cnt++ ] = i;

		cnt = 0;
		for ( i = 0; i < 22; i++ )
			for ( j = i; j < 22; j++ )
				sum[ cnt++ ] = p[ i ] + p[ j ];

		quickSort( sum, 253 );
	}

	return 0;
}

void insertionSort( int *data, int n ) {
	int i, j, tmp;

	for ( i = 1; i < n; i++ ) {
		tmp = data[ i ];

		if ( data[ i - 1 ] > tmp ) {
			j = i;
			do {
				data[ j ] = data[ j - 1 ];

				j--;
			} while ( j && data[ j - 1 ] > tmp );

			data[ j ] = tmp;
		}
	}
}

void quickSort( int *data, int n ) {
	int low[ 30 ] = { 0 }, high[ 30 ] = { n - 1 }, sp = 1;

	while ( sp-- ) {
		int l = low[ sp ], r = high[ sp ];

		if ( l < r ) {
			int i = l, j = r, pivot = median( data[ i ], data[ ( i + j ) / 2 ], data[ j ] );

			while ( 1 ) {
				for ( ; data[ i ] < pivot; i++ ) ;
				for ( ; pivot < data [ j ]; j-- ) ;
				if ( i >= j )
					break;

				SWAP( data[ i ], data[ j ] );

				i++;
				j--;
			}

			if ( i - l < 20 )
				insertionSort( data + l, i - l );
			else {
				low[ sp ] = l;
				high[ sp ] = i - 1;
				sp++;
			}

			if ( r - j < 20 )
				insertionSort( data + j + 1, r - j );
			else {
				low[ sp ] = j + 1;
				high[ sp ] = r;
				sp++;
			}
		}
	}
}

int median( int x, int y, int z ) {
	if ( x < y )
		if ( y < z )
			return y;
		else if ( z < x )
			return x;
		else
			return z;
	else if ( z < y )
		return y;
	else if ( x < z )
		return x;
	else
		return z;
}