题目
题目描述
You are given nn pairwise non-collinear two-dimensional vectors. You can make shapes in the two-dimensional plane with these vectors in the following fashion:
Start at the origin (0, 0)(0,0) .
Choose a vector and add the segment of the vector to the current point. For example, if your current point is at (x, y)(x,y) and you choose the vector (u, v)(u,v) , draw a segment from your current point to the point at (x + u, y + v)(x+u,y+v) and set your current point to (x + u, y + v)(x+u,y+v) .
Repeat step 2 until you reach the origin again.
You can reuse a vector as many times as you want.
Count the number of different, non-degenerate (with an area greater than 00 ) and convex shapes made from applying the steps, such that the shape can be contained within a m \times mm×m square. Since this number can be too large, you should calculate it by modulo 998244353998244353 .
Two shapes are considered the same if there exists some parallel translation of the first shape to another.
A shape can be contained within a m \times mm×m square if there exists some parallel translation of this shape so that every point (u, v)(u,v) inside or on the border of the shape satisfies 0 \leq u, v \leq m0≤u,v≤m .
输入格式
The first line contains two integers nn and mm — the number of vectors and the size of the square ( 1 \leq n \leq 51≤n≤5 , 1 \leq m \leq 10^91≤m≤10
9
).
Each of the next nn lines contains two integers x_ix
i
and y_iy
i
— the xx -coordinate and yy -coordinate of the ii -th vector ( |x_i|, |y_i| \leq 4∣x
i
∣,∣y
i
∣≤4 , (x_i, y_i) \neq (0, 0)(x
i
,y
i
)
=(0,0) ).
It is guaranteed, that no two vectors are parallel, so for any two indices ii and jj such that 1 \leq i < j \leq n1≤i<j≤n , there is no real value kk such that x_i \cdot k = x_jx
i
⋅k=x
j
and y_i \cdot k = y_jy
i
⋅k=y
j
.
输出格式
Output a single integer — the number of satisfiable shapes by modulo 998244353998244353 .
输入输出样例
输入 #1复制
3 3
-1 0
1 1
0 -1
输出 #1复制
3
输入 #2复制
3 3
-1 0
2 2
0 -1
输出 #2复制
1
输入 #3复制
3 1776966
-1 0
3 3
0 -2
输出 #3复制
296161
输入 #4复制
4 15
-4 -4
-1 1
-1 -4
4 3
输出 #4复制
1
输入 #5复制
5 10
3 -4
4 -3
1 -3
2 -3
-3 -4
输出 #5复制
0
输入 #6复制
5 1000000000
-2 4
2 -3
0 -4
2 4
-1 -3
输出 #6复制
9248783
说明/提示
The shapes for the first sample are:
The only shape for the second sample is:
The only shape for the fourth sample is:
思路
因为是凸包,所以如果确定了每个向量的出现次数
c
c
c,那么这些向量的顺序也就确定了。
换言之,需要进行计数的就是满足下列条件的数组
c
c
c,其中
c
i
c_i
ci 表示向量
i
i
i 的出现次数:
∑
i
=
1
n
c
i
x
i
=
0
,
∑
i
=
1
n
c
i
y
i
=
0
\sum_{i=1}^{n}c_ix_i=0,\sum_{i=1}^n c_iy_i=0
∑i=1ncixi=0,∑i=1nciyi=0
从常规的角度来设计状态的话无法绕过
∑
c
x
\sum cx
∑cx 这种形式的状态,所以就需要用到一种非常极端的优化方法。
枚举哪些
c
c
c 的二进制下第
k
k
k位为
1
1
1,那么就可以采用类似数位
d
p
dp
dp 的办法,从低位向高位转移,只存下
∑
c
i
x
i
2
k
\frac{\sum c_ix_i}{2^k}
2k∑cixi 这种形式的状态,而且因为不能转移的状态是不需要储存的,所以只需要保留
∑
c
i
x
i
2
k
≤
∑
x
i
\frac{\sum c_ix_i}{2^k}\leq \sum x_i
2k∑cixi≤∑xi 的状态,而这样的状态是只有
O
(
n
V
)
O(nV)
O(nV) 种的。再状压一下两维与
m
m
m 的关系就可了(后缀是否大于
m
m
m)。
代码
#include<bits/stdc++.h>
#define FOR(i,n) for(int i = 0; i < (n); i += 1)
using namespace std;
constexpr int mod = 998244353;
int x[5],y[5];
int px[32],nx[32],py[32],ny[32];
int dp[32][20][20][20][20][2][2];
void add(int &x,const int& y){
x += y;
if(x >= mod) x -= mod;
}
int main(){
int n,m;
cin >> n >> m;
for(int i = 0; i < n; i += 1)
cin >> x[i] >> y[i];
for(int mask = 0; mask < (1 << n); mask += 1)
for(int i = 0; i < n; i += 1)
if((mask >> i) & 1){
(x[i] > 0 ? px : nx)[mask] += abs(x[i]);
(y[i] > 0 ? py : ny)[mask] += abs(y[i]);
}
dp[0][0][0][0][0][0][0] = 1;
FOR(i,30)FOR(cpx,20)FOR(cnx,20)FOR(cpy,20)FOR(cny,20)
FOR(bx,2)FOR(by,2)FOR(mask,1 << n)
if(dp[i][cpx][cnx][cpy][cny][bx][by]){
if(0)cout << i << " " << cpx << " " << cny << " " << cpy << " " << cny << " " << bx << " " << by << " " << dp[i][cpx][cnx][cpy][cny][bx][by] << endl;
int npx = cpx + px[mask],
nnx = cnx + nx[mask],
npy = cpy + py[mask],
nny = cny + ny[mask];
if((npx ^ nnx) & 1) continue;
if((npy ^ nny) & 1) continue;
int cx = npx & 1,mx = (m >> i) & 1;
int cy = npy & 1,my = (m >> i) & 1;
add(dp[i + 1][npx >> 1][nnx >> 1][npy >> 1][nny >> 1]
[cx != mx ? (cx > mx) : bx][cy != my ? (cy > my) : by],
dp[i][cpx][cnx][cpy][cny][bx][by]);
}
cout << (dp[30][0][0][0][0][0][0] + mod - 1) % mod;
}