Problem:
Score : 700 points

Problem Statement

You are given N points (x_i,y_i) located on a two-dimensional plane.
Consider a subset S of the N points that forms a convex polygon.
Here, we say a set of points S forms a convex polygon when there exists a convex polygon with a positive area that has the same set of vertices as S. All the interior angles of the polygon must be strictly less than 180°.

For example, in the figure above, {A,C,E} and {B,D,E} form convex polygons; {A,C,D,E}, {A,B,C,E}, {A,B,C}, {D,E} and {} do not.

For a given set S, let n be the number of the points among the N points that are inside the convex hull of S (including the boundary and vertices). Then, we will define the score of S as 2^{n-|S|}.

Compute the scores of all possible sets S that form convex polygons, and find the sum of all those scores.

However, since the sum can be extremely large, print the sum modulo 998244353.

Constraints

1≤N≤200

0≤x_i,y_i<10^4 (1≤i≤N)

If i≠j, x_i≠x_j or y_i≠y_j.

x_i and y_i are integers.

Input

The input is given from Standard Input in the following format:

N
x_1 y_1
x_2 y_2
:
x_N y_N

Output

Print the sum of all the scores modulo 998244353.

Sample Input 1

4
0 0
0 1
1 0
1 1

Sample Output 1

5

We have five possible sets as S, four sets that form triangles and one set that forms a square. Each of them has a score of 2^0=1, so the answer is 5.

Sample Input 2

5
0 0
0 1
0 2
0 3
1 1

Sample Output 2

11

We have three "triangles" with a score of 1 each, two "triangles" with a score of 2 each, and one "triangle" with a score of 4. Thus, the answer is 11.

Sample Input 3

1
3141 2718

Sample Output 3

0

There are no possible set as S, so the answer is 0.

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#include "bits/stdc++.h"
using namespace std;
struct point{
	int x , y;
	point(int _x = 0 , int _y = 0){
		x = _x;
		y = _y;
	}
	point operator + (const point &other) const {
		return point(x + other.x , y + other.y);
	}
	point operator - (const point &other) const {
		return point(x - other.x , y - other.y);
	}
	bool operator < (const point &other) const {
		if(x == other.x){
			return y < other.y;
		}
		return x < other.x;
	}
	void read(){
		scanf("%d %d" , &x , &y);
	}
};
inline int dot(point a , point b){
	return a.x * b.x + a.y * b.y;
}
inline int cross(point a , point b){
	return a.x * b.y - a.y * b.x;
}
inline int orient(point a , point b , point c){//orientation of point c with respect to line from a -> b
	int val = cross(b - a , c - a);
	if(val > 0){
		return 1;//c comes anticlockwise on line from a -> b
	}
	if(val < 0){
		return -1;//c comes clockwise on line from a -> b
	}
	return 0;//c is collinear with line from a -> b
}
int dist(point a , point b){
	return dot(a - b , a - b);
}
const int N = 205;
const int mod = 998244353;
const int inv = 499122177;
int pw2[N];
int n;
point arr[N];
vector < point > v;
point bottom;
int ans;
bool cmp(point a , point b){
	int tmp = orient(bottom , a , b);
	if(tmp == -1){
		return 1;
	}
	if(tmp == 1){
		return 0;
	}
	return dist(bottom , a) < dist(bottom , b);
}
bool inside(point p1 , point p2 , point p3 , point q){
	int o1 = orient(p1 , p2 , q);
	int o2 = orient(p2 , p3 , q);
	int o3 = orient(p3 , p1 , q);
	return (o1 == o2) && (o2 == o3) && (o3 != 0);
}
int siz2[N][N][N];
int siz3[N][N];
map < point , int > mp;
vector < int > indexes;
//int tot;
int dp[N][N];
int solve(int last1 , int last2){
	if(dp[last1][last2] != -1){
		return dp[last1][last2];
	}
	int res = !!last1;
	/*if(last1){
		cout << tot << " ";
	}*/
	for(int i = last2 + 1 ; i < v.size() ; ++i){
		if(orient(v[last1] , v[last2] , v[i]) == -1){
			//tot += siz2[indexes[0]][indexes[last1]][indexes[i]] + (last1 ? siz3[indexes[0]][i] : 0);
			res = (res + 1LL * solve(last2 , i) * pw2[siz2[indexes[0]][indexes[last1]][indexes[i]] + (last1 ? siz3[indexes[0]][i] : 0) + siz3[indexes[last2]][indexes[i]]]) % mod;
			//tot -= siz2[indexes[0]][indexes[last1]][indexes[i]] + (last1 ? siz3[indexes[0]][i] : 0);
		}
	}
	return dp[last1][last2] = res;
}
void solve(int idx){
	v.clear();
	bottom.x = arr[idx].x;
	bottom.y = arr[idx].y;
	v.emplace_back(arr[idx]);
	for(int i = 1 ; i <= n ; ++i){
		if(arr[i].y > bottom.y){
			v.emplace_back(arr[i]);
		}
		else if(arr[i].y == bottom.y && arr[i].x > bottom.x){
			v.emplace_back(arr[i]);
		}
	}
	sort(v.begin() + 1 , v.end() , cmp);
	indexes.clear();
	for(int i = 0 ; i < v.size() ; ++i){
		indexes.emplace_back(mp[v[i]]);
	}
	//cout << v.size() << "--\n";
	memset(dp , -1 , sizeof(dp));
	for(int i = 1 ; i < v.size() ; ++i){
		//tot = siz3[indexes[0]][indexes[i]];
		ans = (ans + 1LL * solve(0 , i) * pw2[siz3[indexes[0]][indexes[i]]]) % mod;
		//cout << "WTF\n";
	}
	//cout << ans << endl;
}
void pre(){
	for(int i = 1 ; i <= n ; ++i){
		for(int j = 1 ; j <= n ; ++j){
			if(i == j){
				continue;
			}
			siz3[i][j] = 0;
			int qlx = min(arr[i].x , arr[j].x);
			int qrx = max(arr[i].x , arr[j].x);
			int qly = min(arr[i].y , arr[j].y);
			int qry = max(arr[i].y , arr[j].y);
			for(int k = 1 ; k <= n ; ++k){
				if(k != i && k != j){
					if(arr[k].x >= qlx && arr[k].x <= qrx && arr[k].y >= qly && arr[k].y <= qry && orient(arr[i] , arr[k] , arr[j]) == 0){
						++siz3[i][j];
					}
				}
			}
		}
	}
	for(int i = 1 ; i <= n ; ++i){
		for(int j = i + 1 ; j <= n ; ++j){
			for(int k = j + 1 ; k <= n ; ++k){
				int res = 0;
				for(int l = k + 1 ; l <= n ; ++l){
					res += inside(arr[i] , arr[j] , arr[k] , arr[l]);
				}
				siz2[i][j][k] = siz2[i][k][j] = siz2[j][i][k] = siz2[j][k][i] = siz2[k][i][j] = siz2[k][j][i] = res;
			}
		}
	}
	mp.clear();
	for(int i = 1 ; i <= n ; ++i){
		mp[arr[i]] = i;
	}
}
int main(){
	scanf("%d" , &n);
	for(int i = 1 ; i <= n ; ++i){
		arr[i].read();
	}
	ans = 0;
	pw2[0] = 1;
	for(int i = 1 ; i <= n ; ++i){
		pw2[i] = (2LL * pw2[i - 1]) % mod;
	}
	pre();
	for(int i = 1 ; i <= n ; ++i){
		solve(i);
	}
	printf("%d\n" , ans);
}