1. 程式人生 > >【CodeForces - 271B 】Prime Matrix (素數,預處理打表,思維)

【CodeForces - 271B 】Prime Matrix (素數,預處理打表,思維)

題幹:

You've got an n × m matrix. The matrix consists of integers. In one move, you can apply a single transformation to the matrix: choose an arbitrary element of the matrix and increase it by 1. Each element can be increased an arbitrary number of times.

You are really curious about prime numbers. Let us remind you that a prime number is a positive integer that has exactly two distinct positive integer divisors: itself and number one. For example, numbers 2, 3, 5 are prime and numbers 1, 4, 6 are not.

A matrix is prime if at least one of the two following conditions fulfills:

  • the matrix has a row with prime numbers only;
  • the matrix has a column with prime numbers only;

Your task is to count the minimum number of moves needed to get a prime matrix from the one you've got.

Input

The first line contains two integers n, m (1 ≤ n, m ≤ 500) — the number of rows and columns in the matrix, correspondingly.

Each of the following n lines contains m integers — the initial matrix. All matrix elements are positive integers. All numbers in the initial matrix do not exceed 105.

The numbers in the lines are separated by single spaces.

Output

Print a single integer — the minimum number of moves needed to get a prime matrix from the one you've got. If you've got a prime matrix, print 0.

Examples

Input

3 3
1 2 3
5 6 1
4 4 1

Output

1

Input

2 3
4 8 8
9 2 9

Output

3

Input

2 2
1 3
4 2

Output

0

Note

In the first sample you need to increase number 1 in cell (1, 1). Thus, the first row will consist of prime numbers: 2, 2, 3.

In the second sample you need to increase number 8 in cell (1, 2) three times. Thus, the second column will consist of prime numbers: 11, 2.

In the third sample you don't have to do anything as the second column already consists of prime numbers: 3, 2.

 

題目大意:

   給出定義:素數矩陣是指一個矩陣中存在至少一行和一列全是素數的矩陣。現在給你一個矩陣,你可以選擇矩陣中任意一個元素加1,問最少需要多少次這樣的操作才能把這個矩陣變成一個素數矩陣。

解題報告:

  這題一眼就是一個n^2logn的寫法,,,但是寫這篇題解的時候發現其實是可以n^2的,,但是因為給了個2s所以時間還算寬裕就直接n^2logn了。。

   言歸正傳,其實就是個素數打表然後二分預處理出每個數對應的可以變成的素數的值,同時維護一個求個差的最小值就好了。。說到n^2其實也不難想,,就是把二分的過程給優化掉,,因為預處理的時候就是單調的所以不需要二分查找了做了一些無用的操作。。直接陣列遞推過去就可以了、。(這一招很常用啊,雖然在這一題中不明顯但是有的時候就需要正著遞推一遍反著遞推一遍,線性就可以得到我們想要的東西,,比如還是那個經典題Fountain)

  另外啊這題因為資料量1e5所以打表就用了簡單的nlogn,,懶得寫線性篩了、、、

AC程式碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e6 + 5;
int su[MAX],cnt;
bool isprime[MAX];
int a[550][550];
int qq[550][550];
void prime() {
	memset(isprime,1,sizeof isprime);
	isprime[1]=isprime[0]=0;
	for(int i = 2; i<=MAX; i++) {
		if(isprime[i]) {
			su[++cnt] = i;
			for(int j = 2*i; j<=MAX; j+=i) isprime[j] = 0;
		}
	}
}
int main()
{
	prime();
	int n,m;
	cin>>n>>m;
	for(int i = 1; i<=n; i++) {
		for(int j = 1; j<=m; j++) {
			scanf("%d",&a[i][j]);
		}
	}
	for(int i = 1; i<=n; i++) {
		for(int j = 1; j<=m; j++) {
			int pos = lower_bound(su+1,su+cnt+1,a[i][j]) - su;
			qq[i][j] = su[pos];
		}
	}
	ll minn = 0x3f3f3f3f3f;
	for(int i = 1; i<=n; i++) {
		ll tmp = 0;
		for(int j = 1; j<=m; j++) tmp += qq[i][j] - a[i][j];
		minn = min(minn,tmp);
	}
	for(int j = 1; j<=m; j++) {
		ll tmp = 0;
		for(int i = 1; i<=n; i++) tmp += qq[i][j] - a[i][j];
		minn = min(minn,tmp);
	}
	printf("%lld\n",minn);
	return 0 ;
 }