Problem:
Problem J:
Cruel Bingo
Bingo is a party game played by many players and one game master. Each player is given a bingo card containing
N
2
different numbers in a
N
×
N
grid (typically
N
= 5). The master draws numbers from a lottery one by one during the game. Each time a number is drawn, a player marks a square with that number if it exists. The player’s goal is to have
N
marked squares in a single vertical, horizontal, or diagonal line and then call “Bingo!” The first player calling “Bingo!” wins the game.
In ultimately unfortunate cases, a card can have exactly
N
unmarked squares, or
N
(
N
-1) marked squares, but not a bingo pattern. Your task in this problem is to write a program counting how many such patterns are possible from a given initial pattern, which contains zero or more marked squares.
Input
The input is given in the following format:
N K
x
1
y
1
.
.
.
x
K
y
K
The input begins with a line containing two numbers
N
(1 ≤
N
≤ 32) and
K
(0 ≤
K
≤ 8), which represent the size of the bingo card and the number of marked squares in the initial pattern respectively.
Then
K
lines follow, each containing two numbers
x
i
and
y
i
to indicate the square at (
x
i
,
y
i
) is marked. The coordinate values are zero-based (i.e. 0 ≤
x
i
,
y
i
≤
N
- 1). No pair of marked squares coincides.
Output
Count the number of possible non-bingo patterns with exactly
N
unmarked squares that can be made from the given initial pattern, and print the number in modulo 10007 in a line (since it is supposed to be huge). Rotated and mirrored patterns should be regarded as different and counted each.
Sample Input 1
4 2
0 2
3 1
Output for the Sample Input 1
6
Sample Input 2
4 2
2 3
3 2
Output for the Sample Input 2
6
Sample Input 3
10 3
0 0
4 4
1 4
Output for the Sample Input 3
1127

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
//#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define MOD 10007


enum Type{
	N,
	E,
	S,
	W,
	NE,
	SE,
	NW,
	SW,
};

struct Info{

	int x,y;
};


int SIZE,K;
int POW[9],dp[18][33][4];
bool check_X[32],check_Y[32];
vector<int> STATE;
vector<Info> V;
Info info[8];

void mod_add(int &A,int B){

	A += B;
	A %= MOD;
}


int func(){

	for(int i = 0; i <= SIZE/2+1; i++){
		for(int k = 0; k <= SIZE; k++){
			for(int a = 0; a < POW[2]; a++){

				dp[i][k][a] = 0;
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		check_X[i] = false;
		check_Y[i] = false;
	}

	int first_cross = 0;

	for(int i = 0; i < V.size(); i++){

		if(check_X[V[i].x] || check_Y[V[i].y]){

			return 0;
		}
		check_X[V[i].x] = true;
		check_Y[V[i].y] = true;

		if(V[i].x == V[i].y){ //右上がり

			first_cross |= POW[0];
		}
		if(V[i].x+V[i].y == SIZE-1){ //右下がり

			first_cross |= POW[1];
		}
	}

	int first = 0;
	dp[first][0][first_cross] = 1;
	int last;
	if(SIZE%2 == 0){

		last = SIZE/2-1;
	}else{

		last = SIZE/2;
	}

	int LU = (SIZE-1)/2;
	int RD = SIZE/2;


	int num_X,num_Y;
	int work[8];
	int next_state,mult_X,mult_Y,add,tmp;

	int num_fix = V.size();

	for(int range = first; range <= last; range++){

		num_X = 0;
		num_Y = 0;

		for(int k = LU+1; k <= RD-1; k++){
			if(!check_X[k]){
				num_X++;
			}
			if(!check_Y[k]){

				num_Y++;
			}
		}

		for(int i = 0; i <= SIZE-num_fix; i++){
			for(int state = 0; state < POW[2]; state++){
				if(dp[range][i][state] == 0)continue;

				if(range == first && SIZE%2 == 1){

					mod_add(dp[range+1][i][state],dp[range][i][state]);
					if(!check_X[LU] && !check_Y[LU] && i+1 <= SIZE-num_fix){

						mod_add(dp[range+1][i+1][POW[2]-1],dp[range][i][state]);
					}

				}else{

					for(int k = 0; k < STATE.size(); k++){

						add = 0;

						int ST = STATE[k];
						for(int loop = 0; loop < 8; loop++){
							if(ST & (POW[loop])){

								work[loop] = 1;
								add++;

							}else{

								work[loop] = 0;
							}
						}

						if(i+add > SIZE-num_fix)continue;

						if(range == first && SIZE%2 == 0){
							if(work[N]+work[E]+work[S]+work[W] != 0){

								continue;
							}
						}

						if((check_Y[LU] && (work[SW]+work[S]+work[SE] != 0)) ||
								(check_Y[RD] && (work[NW]+work[N]+work[NE] != 0))){

							continue;
						}
						if((check_X[LU] && (work[NW]+work[W]+work[SW] != 0)) ||
								(check_X[RD] && (work[NE]+work[E]+work[SE] != 0))){

							continue;
						}

						next_state = state;
						if(work[SW] == 1 || work[NE] == 1){

							next_state |= POW[0];
						}
						if(work[NW] == 1 || work[SE] == 1){

							next_state |= POW[1];
						}

						switch(work[N]+work[S]){
						case 2:
							mult_X = (num_X-i)*(num_X-i-1);
							break;
						case 1:
							mult_X = (num_X-i);
							break;
						case 0:
							mult_X = 1;
							break;
						}

						switch(work[E]+work[W]){
						case 2:
							mult_Y = (num_Y-i)*(num_Y-i-1);
							break;
						case 1:
							mult_Y = (num_Y-i);
							break;
						case 0:
							mult_Y = 1;
							break;
						}

						tmp = mult_X*mult_Y;
						tmp *= dp[range][i][state];
						tmp %= MOD;

						mod_add(dp[range+1][i+add][next_state],tmp);
					}
				}
			}
		}

		LU--;
		RD++;
	}

	return dp[last+1][SIZE-num_fix][POW[2]-1];
}

void calc_state(){

	int check[8];

	for(int state = 0; state < POW[8]; state++){
		for(int loop = 0; loop < 8; loop++){
			if(state & (POW[loop])){

				check[loop] = 1;

			}else{

				check[loop] = 0;
			}
		}

		if((check[NW]+check[N]+check[NE] > 1)||(check[NE]+check[E]+check[SE] > 1)||
				(check[SE]+check[S]+check[SW] > 1)||(check[SW]+check[W]+check[NW] > 1)){
			continue;
		}
		STATE.push_back(state);
	}
}


int main(){

	POW[0] = 1;
	for(int i = 1; i <= 8; i++){

		POW[i] = POW[i-1]*2;
	}

	calc_state();

	scanf("%d %d",&SIZE,&K);

	for(int i = 0; i < K; i++){

		scanf("%d %d",&info[i].x,&info[i].y);
	}

	int ans = 0;
	int count,tmp;

	for(int state = 0; state < POW[K]; state++){

		V.clear();
		count = 0;

		for(int loop = 0; loop < K; loop++){
			if(state & POW[loop]){
				V.push_back(info[loop]);
				count++;
			}
		}

		tmp = func();

		if(count%2 == 0){

			ans += tmp;
			ans %= MOD;

		}else{

			ans = (ans-tmp+MOD)%MOD;
		}
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 3268
final_rank: 2

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
//#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define MOD 10007


enum Type{
	N,
	E,
	S,
	W,
	NE,
	SE,
	NW,
	SW,
};

struct Info{

	int x,y;
};


int SIZE,K;
int POW[9],dp[18][33][4];
bool check_X[32],check_Y[32];
vector<int> STATE;
vector<Info> V;
Info info[8];

void mod_add(int &A,int B){

	A += B;
	A %= MOD;
}


int func(){

	for(int i = 0; i <= SIZE/2+1; i++){
		for(int k = 0; k <= SIZE; k++){
			for(int a = 0; a < POW[2]; a++){

				dp[i][k][a] = 0;
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		check_X[i] = false;
		check_Y[i] = false;
	}

	int first_cross = 0;

	for(int i = 0; i < V.size(); i++){

		if(check_X[V[i].x] || check_Y[V[i].y]){

			return 0;
		}
		check_X[V[i].x] = true;
		check_Y[V[i].y] = true;

		if(V[i].x == V[i].y){

			first_cross |= POW[0];
		}else if(V[i].x+V[i].y == SIZE-1){

			first_cross |= POW[1];
		}
	}

	int first = 0;
	dp[first][0][first_cross] = 1;
	int last;
	if(SIZE%2 == 0){

		last = SIZE/2-1;
	}else{

		last = SIZE/2;
	}

	int LU = (SIZE-1)/2;
	int RD = SIZE/2;

	int num_X,num_Y;
	int work[8];
	int next_state,mult_X,mult_Y,add,tmp;

	int num_fix = V.size();

	for(int range = first; range <= last; range++){

		num_X = 0;
		num_Y = 0;

		for(int k = LU+1; k <= RD-1; k++){
			if(!check_X[k]){
				num_X++;
			}
			if(!check_Y[k]){

				num_Y++;
			}
		}

		for(int i = 0; i <= SIZE-num_fix; i++){ //残すセル数のループ
			for(int state = 0; state < POW[2]; state++){
				if(dp[range][i][state] == 0)continue;

				if(range == first && SIZE%2 == 1){

					mod_add(dp[range+1][i][state],dp[range][i][state]);
					if(!check_X[LU] && !check_Y[LU] && i+1 <= SIZE-num_fix){

						mod_add(dp[range+1][i+1][POW[2]-1],dp[range][i][state]);
					}

				}else{

					for(int k = 0; k < STATE.size(); k++){

						add = 0;

						int ST = STATE[k];
						for(int loop = 0; loop < 8; loop++){
							if(ST & (POW[loop])){

								work[loop] = 1;
								add++;

							}else{

								work[loop] = 0;
							}
						}

						if(i+add > SIZE-num_fix)continue;

						if(range == first && SIZE%2 == 0){
							if(work[N]+work[E]+work[S]+work[W] != 0){

								continue;
							}
						}

						if((check_Y[LU] && (work[SW]+work[S]+work[SE] != 0)) ||
								(check_Y[RD] && (work[NW]+work[N]+work[NE] != 0))){

							continue;
						}
						if((check_X[LU] && (work[NW]+work[W]+work[SW] != 0)) ||
								(check_X[RD] && (work[NE]+work[E]+work[SE] != 0))){

							continue;
						}

						next_state = state;
						if(work[SW] == 1 || work[NE] == 1){

							next_state |= POW[0];
						}
						if(work[NW] == 1 || work[SE] == 1){

							next_state |= POW[1];
						}

						switch(work[N]+work[S]){
						case 2:
							mult_X = (num_X-i)*(num_X-i-1);
							break;
						case 1:
							mult_X = (num_X-i);
							break;
						case 0:
							mult_X = 1;
							break;
						}

						switch(work[E]+work[W]){
						case 2:
							mult_Y = (num_Y-i)*(num_Y-i-1);
							break;
						case 1:
							mult_Y = (num_Y-i);
							break;
						case 0:
							mult_Y = 1;
							break;
						}

						tmp = mult_X*mult_Y;
						tmp *= dp[range][i][state];
						tmp %= MOD;

						mod_add(dp[range+1][i+add][next_state],tmp);
					}
				}
			}
		}

		LU--;
		RD++;
	}

	return dp[last+1][SIZE-num_fix][POW[2]-1];
}

void calc_state(){

	int check[8];

	for(int state = 0; state < POW[8]; state++){
		for(int loop = 0; loop < 8; loop++){
			if(state & (POW[loop])){

				check[loop] = 1;

			}else{

				check[loop] = 0;
			}
		}

		if((check[NW]+check[N]+check[NE] > 1)||(check[NE]+check[E]+check[SE] > 1)||
				(check[SE]+check[S]+check[SW] > 1)||(check[SW]+check[W]+check[NW] > 1)){
			continue;
		}
		STATE.push_back(state);
	}
}


int main(){

	POW[0] = 1;
	for(int i = 1; i <= 8; i++){

		POW[i] = POW[i-1]*2;
	}

	calc_state();

	scanf("%d %d",&SIZE,&K);

	for(int i = 0; i < K; i++){

		scanf("%d %d",&info[i].x,&info[i].y);
	}

	int ans = 0;
	int count,tmp;

	for(int state = 0; state < POW[K]; state++){

		V.clear();
		count = 0;

		for(int loop = 0; loop < K; loop++){
			if(state & POW[loop]){
				V.push_back(info[loop]);
				count++;
			}
		}

		tmp = func();

		if(count%2 == 0){

			ans += tmp;
			ans %= MOD;

		}else{

			ans = (ans-tmp+MOD)%MOD;
		}
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 0.17142857142857143
time_ms: 60
memory_kb: 3272
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define FOR(i,a,b) for(int i=int(a);i<int(b);i++)
#define REP(i,b) FOR(i,0,b)
#define MP make_pair
#define PB push_back
#define ALL(x) x.begin(),x.end()
#define REACH cerr<<"reached line "<<__LINE__<<endl
#define DBG(x) cerr<<"line "<<__LINE__<<" "<<#x<<":"<<x<<endl

using uint=unsigned int;
using ll=long long;
using pii=pair<int,int>;
using vi=vector<int>;
using ld=long double;

template<class T,class U>
ostream& operator<<(ostream& os,const pair<T,U>& p){
	os<<"("<<p.first<<","<<p.second<<")";
	return os;
}

template<class T>
ostream& operator <<(ostream& os,const vector<T>& v){
	os<<"[";
	REP(i,(int)v.size()){
		if(i)os<<",";
		os<<v[i];
	}
	os<<"]";
	return os;
}

int read(){
	int i;
	scanf("%d",&i);
	return i;
}

ll readLL(){
	ll i;
	scanf("%lld",&i);
	return i;
}

string readString(){
	static char buf[3341919];
	scanf("%s",buf);
	return string(buf);
}

char* readCharArray(){
	static char buf[3341919];
	static int bufUsed=0;
	char* ret=buf+bufUsed;
	scanf("%s",ret);
	bufUsed+=strlen(ret)+1;
	return ret;
}

template<class T,class U>
void chmax(T& a,U b){
	if(a<b)
		a=b;
}

template<class T,class U>
void chmin(T& a,U b){
	if(a>b)
		a=b;
}

template<class T>
T Sq(const T& t){
	return t*t;
}

const int mod=10007;
template<class T,class U>
void add(T& a,U b){
	a=((ll)a+b)%mod;
}

template<class T,class U>
void sub(T& a,U b){
	a=((ll)a-b%mod+mod)%mod;
}

template<class T,class U>
void mult(T& a,U b){
	a=((ll)a*b)%mod;
}

ll modPow(ll a,ll p){
	ll s=1;
	REP(i,30){
		if((p>>i)&1)
			mult(s,a);
		mult(a,a);
	}
	return s;
}

ll modInv(ll a){
	return modPow(a,mod-2);
}

struct Wafrelka{
	int n,m;
	vector<vi> graph;
	Wafrelka(int _n,int _m):n(_n),m(_m){
		graph.assign(n,vi());
	}
	void AddEdge(int a,int b){
		graph[a].PB(b);
	}
	vi CountMatching(){
		int maxMatch=min(n,m);
		vector<vi> dp(maxMatch+1,vi(1<<m,0));
		dp[0][0]=1;
		REP(i,n)
			for(int j=maxMatch-1;j>=0;j--)
				REP(vis,1<<m)
					for(auto to:graph[i])if(!((vis>>to)&1))
						add(dp[j+1][vis|(1<<to)],dp[j][vis]);
		vi ret(maxMatch+1,0);
		REP(i,maxMatch+1)
			REP(j,1<<m)
				add(ret[i],dp[i][j]);
		return ret;
	}
};

struct Solver{
	int n;
	vector<vi> graph;
	Solver(int _n):n(_n){
		graph.assign(n*2,vi());
	}
	void AddEdge(int a,int b){
		graph[a].PB(b+n);
		graph[b+n].PB(a);
	}
	void dfs(int v,vector<bool>& vis,vi& left,vi& right){
		if(vis[v])
			return;
		if(v<n)
			left.PB(v);
		else
			right.PB(v);
		vis[v]=true;
		for(auto to:graph[v])
			dfs(to,vis,left,right);
	}
	int CountPerfectMatching(){
		vector<bool> vis(n*2,false);
		vi cur(n+1,0),nx(n+1,0);
		cur[0]=1;
		REP(i,n)if(!vis[i]){
			vi left,right;
			dfs(i,vis,left,right);
			Wafrelka w(left.size(),right.size());
			REP(j,left.size())
				for(auto to:graph[left[j]])
					REP(k,right.size())if(to==right[k])
						w.AddEdge(j,k);
			vi t=w.CountMatching();
			fill(ALL(nx),0);
			REP(j,n+1)REP(k,t.size())if(j+k<n+1)
				add(nx[j+k],cur[j]*t[k]);
			swap(cur,nx);
		}
		int c=1,ret=0;
		for(int i=n;i>=0;i--){
			if(i&1)
				sub(ret,cur[i]*c);
			else
				add(ret,cur[i]*c);
			c=c*(n-i+1)%mod;
		}
		return ret;
	}
};

int main(){
	int n=read(),k=read();
	vector<pii> es;
	REP(i,k){
		int x=read(),y=read();
		es.PB(MP(x,y));
	}
	int ans=0;
	{
		vector<vector<bool>> c(n,vector<bool>(n,false));
		for(auto e:es)
			c[e.first][e.second]=true;
		Solver sv(n);
		REP(i,n)REP(j,n)if(c[i][j])
			sv.AddEdge(i,j);
		add(ans,sv.CountPerfectMatching());
	}
	{
		vector<vector<bool>> c(n,vector<bool>(n,false));
		for(auto e:es)
			c[e.first][e.second]=true;
		REP(i,n)
			c[i][i]=true;
		Solver sv(n);
		REP(i,n)REP(j,n)if(c[i][j])
			sv.AddEdge(i,j);
		sub(ans,sv.CountPerfectMatching());
	}
	{
		vector<vector<bool>> c(n,vector<bool>(n,false));
		for(auto e:es)
			c[e.first][e.second]=true;
		REP(i,n)
			c[i][n-1-i]=true;
		Solver sv(n);
		REP(i,n)REP(j,n)if(c[i][j])
			sv.AddEdge(i,j);
		sub(ans,sv.CountPerfectMatching());
	}
	{
		vector<vector<bool>> c(n,vector<bool>(n,false));
		for(auto e:es)
			c[e.first][e.second]=true;
		REP(i,n)
			c[i][i]=true;
		REP(i,n)
			c[i][n-1-i]=true;
		Solver sv(n);
		REP(i,n)REP(j,n)if(c[i][j])
			sv.AddEdge(i,j);
		add(ans,sv.CountPerfectMatching());
	}
	cout<<ans<<endl;
}
accuracy: 1
time_ms: 310
memory_kb: 23432
final_rank: 4

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define all(c) c.begin(),c.end()
#define pb push_back
#define fs first
#define sc second
#define show(x) cout << #x << " = " << x << endl
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)
using namespace std;
int N,mod=10007;
vector<int> _bs;
inline int P(int x,int y){
	if(y==0) return 1;
	if(y==1) return x;
	if(y==2) return x*(x-1);
}
inline void add(int &x,int y){
	x+=y;
	x%=mod;
}
int solve(vector<int> x,vector<int> y){
	int K=x.size();
	int dp[17][33][2][2]={};		//	,put,sl,bsl
	bool banx[32]={},bany[32]={};
	bool sl=0,bsl=0;
	rep(i,K){
		if(banx[x[i]]||bany[y[i]]) return 0;
		banx[x[i]]=bany[y[i]]=1;
		if(x[i]==y[i]) bsl=1;
		if(x[i]+y[i]==N-1) sl=1;
	}
	dp[0][0][sl][bsl]=1;
	int L=-N%2,M=(N+1)/2;
	int A=(N-1)/2,B=N/2;
	rep(i,M){//it
		int X=0,Y=0;
		for(int j=A+1;j<=B-1;j++){
			if(!banx[j]) X++;
			if(!bany[j]) Y++;
		}
		rep(j,N+1-K){//put
			rep(k,2) rep(l,2){//sl,bsl
				if(dp[i][j][k][l]==0) continue;
				if(L==-1){
					add(dp[i+1][j][k][l],dp[i][j][k][l]);
					if(!banx[A]&&!bany[A]&&j+1<=N-K) add(dp[i+1][j+1][1][1],dp[i][j][k][l]);
				}else{
					for(int b:_bs){
						bool bs[8]={};
						int C=0;
						rep(a,8) bs[a]=(b>>a)&1;
						rep(a,8) if(bs[a]) C++;
						if(L==0&&(bs[4]||bs[5]||bs[6]||bs[7])) continue;
						if(banx[A]&&(bs[0]||bs[4]||bs[1])) continue;
						if(banx[B]&&(bs[2]||bs[6]||bs[3])) continue;
						if(bany[A]&&(bs[3]||bs[7]||bs[0])) continue;
						if(bany[B]&&(bs[1]||bs[5]||bs[2])) continue;
						int ad=P(Y-j,bs[4]+bs[6])*P(X-j,bs[5]+bs[7])%mod*dp[i][j][k][l];
						if(ad) add(dp[i+1][j+C][k|bs[1]||bs[3]][l|bs[0]|bs[2]],ad);
					}
				}
			}
		}
		A--,B++,L+=2;
	}
/*	rep(i,M+1) rep(j,N+1-K) rep(k,2) rep(l,2){
		printf("dp[%d][%d][%d][%d]=%d\n",i,j,k,l,dp[i][j][k][l]);
	}
	puts("");*/
	return dp[M][N-K][1][1];
}
int xx[8],yy[8];
int main(){
	rep(i,1<<8){
		bool b[8]={};
		rep(j,8) b[j]=(i>>j)&1;
		bool ok=1;
		if(b[0]+b[4]+b[1]>1) ok=0;
		if(b[1]+b[5]+b[2]>1) ok=0;
		if(b[2]+b[6]+b[3]>1) ok=0;
		if(b[3]+b[7]+b[0]>1) ok=0;
		if(ok) _bs.pb(i);
	}
	int K;
	cin>>N>>K;
	rep(i,K) cin>>xx[i]>>yy[i];
	int ans=0;
	rep(i,1<<K){
		vector<int> x,y;
		rep(j,K) if((i>>j)&1) x.pb(xx[j]),y.pb(yy[j]);
		int t=1;
		if(x.size()%2) t=-1;
		int tmp=solve(x,y)*t;
//		show(i);
//		show(tmp);
		add(ans,tmp);
	}
	cout<<(ans+mod)%mod<<endl;
}
accuracy: 1
time_ms: 120
memory_kb: 1228
final_rank: 3

code_snippet: #include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
int mod=10007;
int r[10];
int c[10];
int n;
int dp[40][40][4];
int dp2[40][40][4][4][5][3];
int v[40][40];
int calc(vector<pair<int,int> > p){
	for(int i=0;i<40;i++)for(int j=0;j<40;j++)for(int k=0;k<4;k++)
		dp[i][j][k]=0;
	for(int i=0;i<p.size();i++)for(int j=i+1;j<p.size();j++){
		if(p[i].first==p[j].first||p[i].second==p[j].second)return 0;
	}
	for(int i=0;i<40;i++)for(int j=0;j<40;j++)v[i][j]=0;
	for(int i=0;i<p.size();i++){
		v[p[i].first][p[i].second]=1;
	}
	dp[0][0][0]=1;
	bool ok=true;
	for(int i=0;i<p.size();i++)if(n/2==p[i].first||n/2==p[i].second)ok=false;
	if(n%2&&ok)dp[0][1][3]=1;
	for(int i=0;i<n/2;i++){
		int hu=0;
		int wu=0;
		int he=0;
		int we=0;
		for(int j=0;j<p.size();j++){
			if(p[j].first==n/2-1-i)he|=1;
			if(p[j].first==(n+1)/2+i)he|=2;
			if(p[j].second==n/2-1-i)we|=1;
			if(p[j].second==(n+1)/2+i)we|=2;
			if(n/2-1-i<p[j].first&&p[j].first<(n+1)/2+i)hu++;
			if(n/2-1-i<p[j].second&&p[j].second<(n+1)/2+i)wu++;
		}
	//	printf("%d: %d %d %d %d\n",i,hu,wu,he,we);
		for(int j=0;j<40;j++){
			for(int k=0;k<4;k++){
				if(!dp[i][j][k])continue;
		//		if(i*2+n%2-j-hu<0||i*2+n%2-j-wu<0)printf("%d %d %d: %d %d %d\n",i,j,k,dp[i][j][k],hu,wu);
				if(i*2+n%2-j-hu<0||i*2+n%2-j-wu<0)continue;
				for(int l=0;l<=4;l++){
					dp[i+1][j+l][k]=(dp[i+1][j+l][k]+dp[i][j][k]*dp2[i*2+n%2-j-hu][i*2+n%2-j-wu][he][we][l][0])%mod;
					dp[i+1][j+l][k|1]=(dp[i+1][j+l][k|1]+dp[i][j][k]*dp2[i*2+n%2-j-hu][i*2+n%2-j-wu][he][we][l][1])%mod;
					dp[i+1][j+l][k|2]=(dp[i+1][j+l][k|2]+dp[i][j][k]*dp2[i*2+n%2-j-hu][i*2+n%2-j-wu][he][we][l][2])%mod;
				}
			}
		}
	}
	int ret=dp[n/2][n-(int)p.size()][3];
	bool t1=false;
	bool t2=false;
	for(int i=0;i<p.size();i++){
		if(p[i].first==p[i].second)t1=true;
		if(p[i].first+p[i].second==n-1)t2=true;
	}
	if(t1)ret=(ret+dp[n/2][n-(int)p.size()][2])%mod;
	if(t2)ret=(ret+dp[n/2][n-(int)p.size()][1])%mod;
	if(t1&&t2)ret=(ret+dp[n/2][n-(int)p.size()][0])%mod;
	return ret;
}
int main(){
	int a,b;
	scanf("%d%d",&a,&b);
	n=a;
	for(int i=0;i<b;i++)scanf("%d%d",r+i,c+i);
	int ret=0;
	for(int i=0;i<40;i++)for(int j=0;j<40;j++){
		for(int k=0;k<4;k++)for(int l=0;l<4;l++){
			dp2[i][j][k][l][0][0]=1;
			int s1=2-__builtin_popcount(k);
			int s2=2-__builtin_popcount(l);
			dp2[i][j][k][l][1][0]=i*s2+j*s1;
			dp2[i][j][k][l][2][0]=(i*(i-1)*(s2/2)+j*(j-1)*(s1/2)+i*j*s1*s2)%mod;
			if(s1==1&&s2==2){
				dp2[i][j][k][l][3][0]=j*i*(i-1)%mod;
			}
			if(s1==2&&s2==1){
				dp2[i][j][k][l][3][0]=i*j*(j-1)%mod;
			}
			if(s1==2&&s2==2){
				dp2[i][j][k][l][3][0]=(j*i*(i-1)+i*j*(j-1))*2%mod;
				dp2[i][j][k][l][4][0]=i*(i-1)*j*(j-1)%mod;
			}
			int t1=0;
			int t2=0;
			if(!(k&1)&&!(l&1))t1++;
			if(!(k&2)&&!(l&2))t1++;
			if(!(k&1)&&!(l&2))t2++;
			if(!(k&2)&&!(l&1))t2++;
			dp2[i][j][k][l][1][1]=t1;
			dp2[i][j][k][l][1][2]=t2;
			if(t1==2){
				dp2[i][j][k][l][2][1]=2*(i+j)+1;
				dp2[i][j][k][l][3][1]=2*i*j;
			}else if(t1==1&&k==0)dp2[i][j][k][l][2][1]=j;
			else if(t1==1&&l==0)dp2[i][j][k][l][2][1]=i;
			if(t2==2){
				dp2[i][j][k][l][2][2]=2*(i+j)+1;
				dp2[i][j][k][l][3][2]=2*i*j;
			}else if(t2==1&&k==0)dp2[i][j][k][l][2][2]=j;
			else if(t2==1&&l==0)dp2[i][j][k][l][2][2]=i;
		}
	}
//	for(int i=0;i<5;i++)for(int j=0;j<5;j++){
//		for(int k=0;k<=4;k++)printf("%d %d %d: %d\n",i,j,k,dp2[i][j][1][0][k][0]);
//	}
	for(int i=0;i<(1<<b);i++){
		int t=__builtin_popcount(i);
		vector<pair<int,int> > p;
		for(int j=0;j<b;j++)if(i&(1<<j))p.push_back(make_pair(r[j],c[j]));
		int val=calc(p);
	//	printf("%d: %d\n",i,val);
		if(t%2)ret=(ret+mod-val)%mod;
		else ret=(ret+val)%mod;
	}
	printf("%d\n",ret);
}
accuracy: 1
time_ms: 10
memory_kb: 2572
final_rank: 1