Problem:
E - 選挙活動
Problem Statement
あなたは次回の選挙の候補者であるX氏の支援者である．
X氏は駅前での街頭演説を予定しており，できるだけ多くの有権者に見てもらえる場所で演説しようと考えている．
駅前は $N$ 個の障害物と $M$ 人の有権者が存在している二次元平面として与えられる．
各障害物は多角形であらわされ，その多角形の内側の領域が障害物となる．多角形の辺上は障害物に含まれない．
また，有権者は平面上の点としてあらわされる．
ある有権者の位置とX氏の位置を結ぶ線分上に障害物が存在しないとき，その有権者はX氏を見ることができる．
あなたの仕事は，駅前の障害物と有権者の情報をもとに，もっとも多くの有権者に見てもらえる地点を探すことだ．
最大で何人の有権者から見えるように演説することができるかを求めよ．
Input
入力は以下のフォーマットで与えられる．
$N$ $M$
$polygon_1$
$polygon_2$
$...$
$polygon_N$
$x_1$ $y_1$
$x_2$ $y_2$
$...$
$x_M$ $y_M$
データセットの最初の行は空白文字1つで区切られた2個の整数 $N$, $M$ からなる．
$N$ $(1 \le N \le 5)$ は駅前にある障害物の個数であり，$M$ $(1 \le M \le 10)$ は駅前にいる有権者の数である．
続く行から $N$ 個の障害物の情報が与えられる．1つの障害物を表す入力は以下の形式で与えられる．
$L$
$x_1$ $y_1$
$x_2$ $y_2$
$...$
$x_L$ $y_L$
各障害物情報の最初の行はその障害物をあらわす多角形に含まれる頂点の数 $L$ である．
その後の $L$ 行には多角形の頂点の座標を表す整数の組が反時計回りに記されている．なお，障害物を構成する頂点数の合計は $15$ 個以下となる．
$N$ 個の障害物の情報の後に続く $M$ 行には有権者のいる座標を表す整数の組が与えられる．
また，各テストケースは以下の条件を満たす：
$ 0 \le |x_i|, |y_i| \le 20 $
多角形の頂点または有権者のいる場所の座標はすべて互いに異なる．
多角形の頂点または有権者のいる場所の座標のうち3点が同一直線状に存在することはない．
2つの異なる多角形同士は交差を持たない．
各多角形は自己交差を持たない．
多角形の内部に有権者が存在することはない．
Output
最大で何人の有権者が演説を見られるようになるかを1行に出力せよ．
Sample Input 1
1 2
4
5 5
15 5
15 15
5 15
0 10
20 10
Output for the Sample Input 1
2
Sample Input 2
1 2
6
0 0
20 0
12 9
20 20
0 20
8 11
1 10
19 10
Output for the Sample Input 2
1
Sample Input 3
4 2
3
0 0
20 0
20 1
3
0 18
19 19
19 20
3
3 2
4 2
4 17
3
16 3
17 3
17 18
2 9
18 10
Output for the Sample Input 3
1
Sample Input 4
3 3
3
0 -2
-1 -3
-1 -6
3
2 2
3 2
4 3
3
-4 4
-4 5
-5 6
0 -3
3 3
-5 5
Output for the Sample Input 4
3
Sample Input 5
2 2
4
2 0
1 2
-1 2
-2 0
4
3 3
3 4
-3 4
-3 3
2 1
-2 1
Output for the Sample Input 5
2
Sample Input 6
1 1
4
1 1
-1 1
-1 -1
1 -1
0 2
Output for the Sample Input 6
1
各入力例の障害物および有権者の配置は，それぞれ以下の図のようになっている．

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
      
#define FOR(i,a,b) for( ll i = (a); i < (ll)(b); i++ )
#define REP(i,n) FOR(i,0,n)
#define YYS(x,arr) for(auto& x:arr)
#define ALL(x) (x).begin(),(x).end()
#define SORT(x) sort( (x).begin(),(x).end() )
#define REVERSE(x) reverse( (x).begin(),(x).end() )
#define UNIQUE(x) (x).erase( unique( ALL( (x) ) ) , (x).end() )
#define PW(x) (1LL<<(x))
#define SZ(x) ((ll)(x).size())
#define SHOW(x) cout << #x << " = " << x << endl
#define SHOWA(x,n) for( int yui = 0; yui < n; yui++ ){ cout << x[yui] << " "; } cout << endl

#define pb emplace_back
#define fi first
#define se second

using namespace std;

typedef long double ld;
typedef long long int ll;
typedef pair<int,int> pi;
typedef pair<ll,ll> pl;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<bool> vb;
typedef vector<ld> vd;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<vpl> gr;
typedef vector<vl> ml;
typedef vector<vd> md;
typedef vector<vi> mi;
     
const ll INF = (ll)1e9 + 10;
const ll INFLL = (ll)1e18 + 10;
const ld EPS = 1e-8;
const ll MOD = 1e9+7;
     
template<class T> T &chmin( T &a , const T &b ){ return a = min(a,b); }
template<class T> T &chmax( T &a , const T &b ){ return a = max(a,b); }
template<class T> inline T sq( T a ){ return a * a; }

ll in(){ long long int x; scanf( "%lld" , &x ); return x; }
char yuyushiki[1000010]; string stin(){ scanf( "%s" , yuyushiki ); return yuyushiki; }

// head



#define X real()
#define Y imag()

#define curr(P,i) P[i]
#define next(P,i) P[(i+1)%P.size()]

typedef complex<ld> P;
typedef vector<P> Pol;

namespace std{
  template<class T> bool operator<(const complex<T> &a , const complex<T> &b ){
    return a.X == b.X ? a.Y < b.Y : a.X < b.X;
  }
}

const ld PI = atan(1)*4.0;

struct L : public vector<P> {
  L( const P a , const P b ){
    pb( a ); pb( b );
  }
  L(){}
};

struct C{
  P p; ld r;
  C( const P p , ld r ) : p(p) , r(r) {}
  C(){}
};

inline ld det( const P &a , const P &b ){
  return imag(conj(a)*b);
}
inline ld dot( const P &a , const P &b ){
  return real(conj(a)*b);
}

inline P unit( const P &a ){
  return a / abs( a );
}

inline ld arg( const P &p ){
  return atan2l( p.Y , p.X );
}

inline P ort( P a ){
  return P( -a.Y , a.X );
}

inline P mid( const P a , const P b ){
  return ( a + b ) * (ld)0.5;
}

ld dtor( ld d ){
  return d * PI / 180.0;
}

int ccw( P a , P b , P c ){
  b -= a; c -= a;
  if( det( b , c ) >  EPS )     return +1; // counter clockwise
  if( det( b , c ) < -EPS )     return -1; // clockwise
  if( dot( b , c ) < -EPS )     return +2; // c--a--b on line
  if( norm(b) < norm(c) - EPS ) return -2; // a--b--c on line
  return 0;
}

bool intersectLL( const L &l , const L &m ){
  return abs( det( l[1] - l[0] , m[1] - m[0] ) ) > EPS || abs( det( l[1] - l[0] , m[0] - l[0] ) ) < EPS;
}

bool parallel( const L l , const L m ){
  return abs( det( l[1] - l[0] , m[1] - m[0] ) ) < EPS;
}

bool intersectSP( const L &s , const P &p ){
  return abs( s[0] - p ) + abs( s[1] - p ) - abs( s[1] - s[0] ) < EPS;
}

bool intersectLP( const L l , const P p ){
  return abs( det( l[1] - p , l[0] - p ) ) < EPS;
}

// not including touch
bool intersectSS( const L s , const L t ){
  return ccw( s[0] , s[1] , t[0] ) * ccw( s[0] , s[1] , t[1] ) < 0 && ccw( t[0] , t[1] , s[0] ) * ccw( t[0] , t[1] , s[1] ) < 0;
}

bool intersectLS( const L l , const L s ){
  return det( l[1] - l[0] , s[0] - l[0] ) * det( l[1] - l[0] , s[1] - l[0] ) < EPS;
}

P projection( const L &l , const P &p ){
  ld t = dot( p - l[0] , l[1] - l[0] ) / norm( l[1] - l[0] );
  return l[0] + t * ( l[1] - l[0] );
}

P symmetry( const L l , const P p ){
  P proj = projection( l , p );
  return proj + ( proj - p );
}

ld distanceSP( const L &s , const P &p ){
  const P r = projection( s , p );
  if( intersectSP( s , r ) ) return abs( r - p );
  return min( abs( s[0] - p ) , abs( s[1] - p ) );
}

ld distanceLP( const L &s , const P &p ){
  return abs( p - projection(s,p) );
}

ld distanceSS( const L s , const L t ){
  if( intersectSS( s , t ) ) return 0;
  return min( min( distanceSP( s , t[0] ) , distanceSP( s , t[1] ) ) , min( distanceSP( t , s[0] ) , distanceSP( t , s[1] ) ) );
}

P crosspoint( const L &l , const L &m ){
  ld a = det( l[1] - l[0] , m[1] - m[0] );
  ld b = det( l[1] - l[0] , l[1] - m[0] );
  if( abs(a) < EPS && abs(a) < EPS ) return m[0];
  if( abs(a) < EPS ) assert(false);
  return m[0] + b / a * (m[1]-m[0]);
}

P rotate( P p , ld t ){
  return p * exp( t * P( 0 , 1 ) );
}

Pol rotate( Pol pol , ld t ){
  YYS( p , pol ) p = rotate( p , t );
  return pol;
}

P rotate( P p , P c , ld t ){
  return rotate( p - c , t ) + c;
}

int getintersectCC( const C c , const C d ){
  ld di = abs( c.p - d.p );
  if( di < EPS && fabsl( c.r - d.r ) < EPS ) return -1; // same
  if( di < fabsl( c.r - d.r ) - EPS ) return 0; // completely inside
  if( di < fabsl( c.r - d.r ) + EPS ) return 1; // inscribed
  if( di < fabsl( c.r + d.r ) - EPS ) return 2; // intersect
  if( di < fabsl( c.r + d.r ) + EPS ) return 3; // outscribed
  return 4; // completely outside
}

// include touch
bool intersectCC( const C c , const C d ){
  int res = getintersectCC( c , d );
  return 1 <= res && res <= 3;
}

pair<P,P> crosspoint( const C c , const C d ){
  int res = getintersectCC( c , d );
  assert( 1 <= res && res <= 3 );
  if( res == 1 || res == 3 ){
    P p = c.p + unit( d.p - c.p ) * c.r;
    if( abs( d.p - p ) < d.r - EPS ) p = c.p + unit( c.p - d.p ) * c.r;
    return make_pair( p , p );
  }
  ld di = abs( c.p - d.p );
  ld a = acos(( c.r * c.r + di * di - d.r * d.r ) / ( 2 * c.r * di ));
  ld t = arg( d.p - c.p );
  return make_pair( c.p + rotate( P( c.r , 0 ) , t+a ) , c.p + rotate( P( c.r , 0 ) , t-a ) );
}

int intersectCL( const C &c , const L &l ){
  ld di = distanceLP( l , c.p );
  if( di < c.r - EPS ) return 1; // completely intersect
  if( di < c.r + EPS ) return 2; // touch
  return 0;
}

pair<P,P> crosspoint( const C &c , const L &l ){
  assert( intersectCL( c , l ) );
  P pr = projection( l , c.p );
  P e = unit( l[0] - l[1] );
  ld base = sqrtl( c.r * c.r - norm( pr - c.p ) );
  return make_pair( pr + e * base , pr - e * base );
}

int containCP( const C &c , const P &p ){
  ld di = abs( c.p - p );
  if( di < c.r - EPS ) return 1; // completely inside
  if( di < c.r + EPS ) return 2; // touch
  return 0;
}

pair<P,P> tangent_point( const C c , const P p ){
  return crosspoint( c , C( mid(c.p,p) , abs(p-c.p)/2 ) );
}

pair<L,L> tangent( const C c , const P p ){
  pair<P,P> cp = tangent_point( c , p );
  return make_pair( L( p , cp.fi ) , L( p , cp.se ) );
}

// First : left , second : right
vector<Pol> convex_cut( const Pol pol, L l ){
  vector<Pol> Q(2);
  REP( i , pol.size() ){
    P a = curr(pol,i), b = next(pol,i);
    if( ccw(l[0] , l[1] , a ) != -1 ) Q[0].pb( a );
    if( ccw(l[0] , l[1] , a ) != 1  ) Q[1].pb( a );
    if( ccw(l[0] , l[1] , a )*ccw(l[0] , l[1] , b ) < 0 ){
      Q[0].pb( crosspoint( L(a,b) , l ) );
      Q[1].pb( crosspoint( L(a,b) , l ) );
    }
  }
  return Q;
}

ld area( const Pol &pol ){
  ld a = 0;
  REP( i , pol.size() ) a += det( curr(pol,i) , next(pol,i) );
  return a/2;
}

enum{ OUT , ON , IN };
int contains( const Pol pol, const P p) {
  bool in = false;
  REP( i , SZ(pol) ){
    P a = curr(pol,i) - p, b = next(pol,i) - p;
    if (imag(a) > imag(b)) swap(a, b);
    if (imag(a) < EPS && EPS < imag(b))
      if( det(a, b) < -EPS) in = !in;
    if( abs( det( a , b ) ) < EPS && dot( a , b ) < EPS ) return ON;
  }
  return in ? IN : OUT;
}

P bisector( P a , P b ){
  P res = unit(a) + unit(b); // making diamond
  return unit( res );
}


L parp( const P p , const P q ){
  P md = mid( p , q );
  P d = rotate( unit( q - p ) , PI / 2 );
  return L( md , md + d );
}

P sym( const L l , const P p ){
  P pr = projection( l , p );
  return p + ld(2) * ( pr - p );
}


Pol convex_hull( vector<P> ps ){
  int n = SZ(ps);
  int k = 0;
  SORT( ps );
  Pol ch( 2*n );
  for( int i = 0; i < n; ch[k++] = ps[i++] )
    while( k >= 2 && ccw( ch[k-2] , ch[k-1] , ps[i] ) <= 0 ) k--;
  for( int i = n-2, t = k+1; i >= 0; ch[k++] = ps[i--] )
    while( k >= t && ccw( ch[k-2] , ch[k-1] , ps[i] ) <= 0 ) k--;
  ch.resize( k-1 );
  return ch;
}


int n, m;

Pol pol[72];

int it;
L ls[1000];

P p[72];

vector<P> all;

vector<P> cand;

int main(){

  n = in();
  m = in();

  REP( i , n ){
    int a = in();
    REP( j , a ){
      int x = in();
      int y = in();
      pol[i].pb( P( x , y ) );
      all.pb( P( x , y ) );
    }
  }

  REP( i , m ){
    int x = in();
    int y = in();
    p[i] = P( x , y );
    all.pb( p[i] );
  }

  REP( i , SZ(all) ){
    REP( j , i ){
      ls[it++] = L( all[i] , all[j] );
    }
  }

  REP( i , it ){
    REP( j , i ){
      if( !parallel( ls[i] , ls[j] ) ){
        cand.pb( crosspoint( ls[i] , ls[j] ) );
      }
    }
  }

  int ans = 0;
  YYS( w , cand ){
    int cnt = 0;
    REP( i , m ){
      L l = L( w , p[i] );
      bool ok = true;
      REP( j , n ){
        REP( k , SZ(pol[j]) ){
          P cur = curr( pol[j] , k );
          P nex = next( pol[j] , k );
          L ll = L( cur , nex );
          if( intersectSS( l , ll ) ){
            ok = false;
            break;
          }
        }
        P nw = w + unit( p[i] - w ) * ( 3 * EPS );
        if( contains( pol[j] , nw ) ){
          ok = false;
        }
        if( !ok ){
          break;
        }
      }
      if( ok ){
        cnt++;
      }
    }
    chmax( ans , cnt );
  }

  cout << ans << endl;
  
  return 0;
}
accuracy: 1
time_ms: 860
memory_kb: 5324
final_rank: 15

code_snippet: #include <bits/stdc++.h>

using namespace std;

using ld = long double;

const ld eps = 1e-9;

struct pt {
    ld x = 0;
    ld y = 0;

    pt operator-(const pt& o) const {
        return {x - o.x, y - o.y};
    }

    pt operator+(const pt& o) const {
        return {x + o.x, y + o.y};
    }

    pt operator*(ld coef) const {
        return {x * coef, y * coef};
    }

    ld vector_mul(const pt& o) const {
        return x * o.y - o.x * y;
    }
};

optional<pt> intersect_lines(pt a, pt b, pt c, pt d) {
    pt ab = b - a;
    pt cd = d - c;
    // [a + ab * t - c, cd] = 0
    // [a - c, cd] + t * [ab, cd] = 0
    // t = [cd, a - c] / [ab, cd]
    ld vm = ab.vector_mul(cd);
    if (abs(vm) < eps) return nullopt;
    ld t = cd.vector_mul(a - c) / vm;
    return a + ab * t;
}

bool are_segs_intersected(pt a, pt b, pt c, pt d) {
    ld vm1, vm2;
    vm1 = (b - a).vector_mul(c - a);
    vm2 = (b - a).vector_mul(d - a);
    if (vm1 < eps && vm2 < eps) return false;
    if (vm1 > -eps && vm2 > -eps) return false;
    vm1 = (d - c).vector_mul(a - c);
    vm2 = (d - c).vector_mul(b - c);
    if (vm1 < eps && vm2 < eps) return false;
    if (vm1 > -eps && vm2 > -eps) return false;
    return true;
}

signed main() {

#ifdef LOCAL
    freopen("input.txt", "r", stdin);
#endif

    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int n, m;
    cin >> n >> m;

    vector<vector<pt>> Ps(n);
    for (int i = 0; i < n; ++i) {
        int sz;
        cin >> sz;
        Ps[i].resize(sz);
        for (pt& p : Ps[i]) cin >> p.x >> p.y;
    }

    vector<pt> a(m);
    for (pt& p : a) cin >> p.x >> p.y;

    vector<pt> all_pts;
    for (auto P : Ps) copy(P.begin(), P.end(), back_inserter(all_pts));

    {
        vector<pt> add_pts;
        for (pt A : a) {
            for (pt C : a) {
                for (pt B : all_pts) {
                    for (pt D : all_pts) {
                        if (auto I = intersect_lines(A, B, C, D); I.has_value()) {
                            add_pts.push_back(I.value());
                        }
                    }
                }
            }
        }
        copy(add_pts.begin(), add_pts.end(), back_inserter(all_pts));
    }

    copy(a.begin(), a.end(), back_inserter(all_pts));

    auto check = [&](pt q, pt p) -> bool {
        for (auto P : Ps) {
            int sz = (int) P.size();
            for (int i = 0; i < sz; ++i) {
                int j = (i + 1) % sz;
                if (are_segs_intersected(q, p, P[i], P[j])) {
                    return false;
                }
            }
        }
        return true;
    };

    int res = 0;
    for (pt q : all_pts) {
        int tmp = 0;
        for (pt p : a) {
            if (check(q, p)) {
                ++tmp;
            }
        }
        res = max(res, tmp);
    }
    cout << res << "\n";

    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 5552
final_rank: 14

code_snippet: // AOJ #2742
// Campaign 2025.2.11

#include <bits/stdc++.h>
using namespace std;
const double EPS = 1e-9;
 
struct Point { double x, y; };
struct Line { Point origin, dir; };

Point operator+(const Point &a, const Point &b) { return {a.x+b.x, a.y+b.y}; }
Point operator-(const Point &a, const Point &b) { return {a.x-b.x, a.y-b.y}; }
Point operator*(const Point &a, double c) { return {a.x*c, a.y*c}; }
Point operator*(double c, const Point &a) { return {a.x*c, a.y*c}; }
Point operator/(const Point &a, double c) { return {a.x/c, a.y/c}; }
 
double dot(const Point &a, const Point &b) {
    return a.x*b.x + a.y*b.y;
}
 
double cross(const Point &a, const Point &b) {
    return a.x*b.y - a.y*b.x;
}
 
bool nearlyEqual(double a, double b, double eps = EPS){
    return fabs(a-b) < eps;
}
 
bool onSegment(const Point &p, const Point &a, const Point &b) {
    if(fabs(cross(p - a, b - a)) > EPS) return false;
    if((p.x - a.x)*(p.x - b.x) > EPS) return false;
    if((p.y - a.y)*(p.y - b.y) > EPS) return false;
    return true;
}
 
bool pointInPolygon(const Point &p, const vector<Point> &poly) {
    bool inside = false;
    int n = poly.size();
    for (int i = 0; i < n; i++){
        Point A = poly[i], B = poly[(i+1)%n];
        if(onSegment(p, A, B)) return true;
        bool cond1 = (A.y > p.y) != (B.y > p.y);
        if(cond1){
            double xInt = A.x + (B.x - A.x)*(p.y - A.y)/(B.y - A.y);
            if(p.x < xInt) inside = !inside;
        }
    }
    return inside;
}
 
bool pointInPolygonStrict(const Point &p, const vector<Point> &poly) {
    int n = poly.size();
    for (int i = 0; i < n; i++){
        if(onSegment(p, poly[i], poly[(i+1)%n])) return false;
    }
    bool inside = false;
    for (int i = 0; i < n; i++){
        Point A = poly[i], B = poly[(i+1)%n];
        bool cond1 = (A.y > p.y) != (B.y > p.y);
        if(cond1){
            double xInt = A.x + (B.x - A.x)*(p.y - A.y)/(B.y - A.y);
            if(p.x < xInt) inside = !inside;
        }
    }
    return inside;
}
 
bool computeLineIntersection(const Point &p, const Point &r, const Point &q, const Point &s, Point &res) {
    double rxs = cross(r, s);
    if(fabs(rxs) < EPS) return false;
    double t = cross(q - p, s) / rxs;
    res = p + r * t;
    return true;
}
 
bool checkSegmentVisibilityForPoly(const Point &V, const Point &X, const vector<Point> &poly) {
    Point r = X - V;
    int n = poly.size();
    vector<double> ts;
    for (int i = 0; i < n; i++){
        Point A = poly[i], B = poly[(i+1)%n];
        Point seg = B - A;
        double rxs = cross(r, seg);
        if(fabs(rxs) < EPS) continue;
        double t_val = cross(A - V, seg) / rxs;
        double u_val = cross(A - V, r) / rxs;
        if(t_val > EPS && t_val < 1 - EPS && u_val > -EPS && u_val < 1 + EPS){
            ts.push_back(t_val);
        }
    }
    sort(ts.begin(), ts.end());
    vector<double> uniq;
    for(double val : ts){
        if(uniq.empty() || fabs(val - uniq.back()) > EPS)
            uniq.push_back(val);
    }
    double start = 0.0;
    for(double t_val : uniq){
        if(t_val - start > EPS){
            double mid = (start + t_val) / 2.0;
            Point midPoint = V + r * mid;
            if(pointInPolygonStrict(midPoint, poly)) return false;
        }
        start = t_val;
    }
    if(1.0 - start > EPS){
        double mid = (start + 1.0) / 2.0;
        Point midPoint = V + r * mid;
        if(pointInPolygonStrict(midPoint, poly)) return false;
    }
    return true;
}
 
bool checkSegmentVisibility(const Point &V, const Point &X, const vector<vector<Point>> &obstacles) {
    for(auto &poly : obstacles){
        if(!checkSegmentVisibilityForPoly(V, X, poly))
            return false;
    }
    return true;
}
 
bool inFreeSpace(const Point &p, const vector<vector<Point>> &obstacles) {
    for(auto &poly : obstacles){
        if(pointInPolygonStrict(p, poly)) return false;
    }
    return true;
}
 
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
 
    int N, M;
    cin >> N >> M;
 
    vector<vector<Point>> obstacles;
    vector<Point> allObstacleVertices;
    for (int i=0; i<N; i++){
        int L;
        cin >> L;
        vector<Point> poly(L);
        for (int j=0; j<L; j++) cin >> poly[j].x >> poly[j].y;
        obstacles.push_back(poly);
        for(auto &p : poly) allObstacleVertices.push_back(p);
    }
 
    vector<Point> voters(M);
    for (int i=0; i<M; i++) cin >> voters[i].x >> voters[i].y;
 
    vector<Point> candidates;
    for (auto &v : voters) candidates.push_back(v);
    for (auto &p : allObstacleVertices) candidates.push_back(p);
 
    struct LStruct { Point origin; Point dir; };
    vector<LStruct> lines;
    for (int i=0; i<M; i++){
        for (auto &obsV : allObstacleVertices) {
            if(nearlyEqual(voters[i].x, obsV.x) && nearlyEqual(voters[i].y, obsV.y))
                continue;
            LStruct L;
            L.origin = voters[i];
            L.dir = obsV - voters[i];
            lines.push_back(L);
        }
    }
    int Lsize = lines.size();
    for (int i = 0; i < Lsize; i++){
        for (int j = i+1; j < Lsize; j++){
            Point inter;
            if(computeLineIntersection(lines[i].origin, lines[i].dir,
                                       lines[j].origin, lines[j].dir, inter)){
                candidates.push_back(inter);
            }
        }
    }
 
    vector<Point> uniq;
    for (auto &p : candidates) {
        bool dup = false;
        for (auto &q : uniq) {
            if(nearlyEqual(p.x, q.x) && nearlyEqual(p.y, q.y)){
                dup = true; break;
            }
        }
        if(!dup) uniq.push_back(p);
    }
    candidates = uniq;
 
    int best = 0;
    for (auto &cand : candidates) {
        if(!inFreeSpace(cand, obstacles)) continue;
        int cnt = 0;
        for (auto &v : voters) {
            if(checkSegmentVisibility(v, cand, obstacles)) cnt++;
        }
        best = max(best, cnt);
        if(best == M) break;
    }
    cout << best << endl;
    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 3844
final_rank: 9

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

#include <unistd.h>

namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf


uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio


using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

/**
 * @brief Fast IO
 */

using T = double;
const T eps = 1e-12;
using Point = complex<T>;
using Poly = vector<Point>;
#define X real()
#define Y imag()
template <typename T> inline bool eq(const T &a, const T &b) {
    return fabs(a - b) < eps;
}
bool cmp(const Point &a, const Point &b) {
    auto sub = [&](Point a) {
        return (a.Y < 0 ? -1 : (a.Y == 0 && a.X >= 0 ? 0 : 1));
    };
    if (sub(a) != sub(b))
        return sub(a) < sub(b);
    return a.Y * b.X < a.X * b.Y;
}
struct Line {
    Point a, b, dir;
    Line() {}
    Line(Point _a, Point _b) : a(_a), b(_b), dir(b - a) {}
    Line(T A, T B, T C) {
        if (eq(A, .0)) {
            a = Point(0, C / B), b = Point(1 / C / B);
        } else if (eq(B, .0)) {
            a = Point(C / A, 0), b = Point(C / A, 1);
        } else {
            a = Point(0, C / B), b = Point(C / A, 0);
        }
    }
};
struct Segment : Line {
    Segment() {}
    Segment(Point _a, Point _b) : Line(_a, _b) {}
};
struct Circle {
    Point p;
    T r;
    Circle() {}
    Circle(Point _p, T _r) : p(_p), r(_r) {}
};

istream &operator>>(istream &is, Point &p) {
    T x, y;
    is >> x >> y;
    p = Point(x, y);
    return is;
}
ostream &operator<<(ostream &os, Point &p) {
    os << fixed << setprecision(12) << p.X << ' ' << p.Y;
    return os;
}
Point unit(const Point &a) {
    return a / abs(a);
}
T dot(const Point &a, const Point &b) {
    return a.X * b.X + a.Y * b.Y;
}
T cross(const Point &a, const Point &b) {
    return a.X * b.Y - a.Y * b.X;
}
Point rot(const Point &a, const T &theta) {
    return Point(cos(theta) * a.X - sin(theta) * a.Y,
                 sin(theta) * a.X + cos(theta) * a.Y);
}
Point rot90(const Point &a) {
    return Point(-a.Y, a.X);
}
T arg(const Point &a, const Point &b, const Point &c) {
    double ret = acos(dot(a - b, c - b) / abs(a - b) / abs(c - b));
    if (cross(a - b, c - b) < 0)
        ret = -ret;
    return ret;
}

Point Projection(const Line &l, const Point &p) {
    T t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}
Point Projection(const Segment &l, const Point &p) {
    T t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}
Point Reflection(const Line &l, const Point &p) {
    return p + (Projection(l, p) - p) * 2.;
}
int ccw(const Point &a, Point b, Point c) {
    b -= a;
    c -= a;
    if (cross(b, c) > eps)
        return 1; // ccw

    if (cross(b, c) < -eps)
        return -1; // cw

    if (dot(b, c) < 0)
        return 2; // c,a,b

    if (norm(b) < norm(c))
        return -2; // a,b,c

    return 0;      // a,c,b

}
bool isOrthogonal(const Line &a, const Line &b) {
    return eq(dot(a.b - a.a, b.b - b.a), .0);
}
bool isParallel(const Line &a, const Line &b) {
    return eq(cross(a.b - a.a, b.b - b.a), .0);
}
bool isIntersect(const Segment &a, const Segment &b) {
    return ccw(a.a, a.b, b.a) * ccw(a.a, a.b, b.b) < 0 and
           ccw(b.a, b.b, a.a) * ccw(b.a, b.b, a.b) < 0;
}
int isIntersect(const Circle &a, const Circle &b) {
    T d = abs(a.p - b.p);
    if (d > a.r + b.r + eps)
        return 4;
    if (eq(d, a.r + b.r))
        return 3;
    if (eq(d, abs(a.r - b.r)))
        return 1;
    if (d < abs(a.r - b.r) - eps)
        return 0;
    return 2;
}
T Dist(const Line &a, const Point &b) {
    Point c = Projection(a, b);
    return abs(c - b);
}
T Dist(const Segment &a, const Point &b) {
    if (dot(a.b - a.a, b - a.a) < eps)
        return abs(b - a.a);
    if (dot(a.a - a.b, b - a.b) < eps)
        return abs(b - a.b);
    return abs(cross(a.b - a.a, b - a.a)) / abs(a.b - a.a);
}
T Dist(const Segment &a, const Segment &b) {
    if (isIntersect(a, b))
        return .0;
    T res = min({Dist(a, b.a), Dist(a, b.b), Dist(b, a.a), Dist(b, a.b)});
    return res;
}
Point Intersection(const Line &a, const Line &b) {
    T d1 = cross(a.b - a.a, b.b - b.a);
    T d2 = cross(a.b - a.a, a.b - b.a);
    if (eq(d1, 0.) and eq(d2, 0.))
        return b.a;
    return b.a + (b.b - b.a) * (d2 / d1);
}
Poly Intersection(const Circle &a, const Line &b) {
    Poly res;
    T d = Dist(b, a.p);
    if (d > a.r + eps)
        return res;
    Point h = Projection(b, a.p);
    if (eq(d, a.r)) {
        res.push_back(h);
        return res;
    }
    Point e = unit(b.b - b.a);
    T ph = sqrt(a.r * a.r - d * d);
    res.push_back(h - e * ph);
    res.push_back(h + e * ph);
    return res;
}
Poly Intersection(const Circle &a, const Segment &b) {
    Line c(b.a, b.b);
    Poly sub = Intersection(a, c);
    double xmi = min(b.a.X, b.b.X), xma = max(b.a.X, b.b.X);
    double ymi = min(b.a.Y, b.b.Y), yma = max(b.a.Y, b.b.Y);
    Poly res;
    rep(i, 0, sub.size()) {
        if (xmi <= sub[i].X + eps and sub[i].X - eps <= xma and
            ymi <= sub[i].Y + eps and sub[i].Y - eps <= yma) {
            res.push_back(sub[i]);
        }
    }
    return res;
}
Poly Intersection(const Circle &a, const Circle &b) {
    Poly res;
    int mode = isIntersect(a, b);
    T d = abs(a.p - b.p);
    if (mode == 4 or mode == 0)
        return res;
    if (mode == 3) {
        T t = a.r / (a.r + b.r);
        res.push_back(a.p + (b.p - a.p) * t);
        return res;
    }
    if (mode == 1) {
        if (b.r < a.r - eps) {
            res.push_back(a.p + (b.p - a.p) * (a.r / d));
        } else {
            res.push_back(b.p + (a.p - b.p) * (b.r / d));
        }
        return res;
    }
    T rc = (a.r * a.r + d * d - b.r * b.r) / d / 2.;
    T rs = sqrt(a.r * a.r - rc * rc);
    if (a.r - abs(rc) < eps)
        rs = 0;
    Point e = unit(b.p - a.p);
    res.push_back(a.p + rc * e + rs * e * Point(0, 1));
    res.push_back(a.p + rc * e + rs * e * Point(0, -1));
    return res;
}
Poly HalfplaneIntersection(vector<Line> &H) {
    sort(ALL(H), [&](Line &l1, Line &l2) { return cmp(l1.dir, l2.dir); });
    auto outside = [&](Line &L, Point p) -> bool {
        return cross(L.dir, p - L.a) < -eps;
    };
    deque<Line> deq;
    int sz = 0;
    rep(i, 0, SZ(H)) {
        while (sz > 1 and
               outside(H[i], Intersection(deq[sz - 1], deq[sz - 2]))) {
            deq.pop_back();
            sz--;
        }
        while (sz > 1 and outside(H[i], Intersection(deq[0], deq[1]))) {
            deq.pop_front();
            sz--;
        }
        if (sz > 0 and fabs(cross(H[i].dir, deq[sz - 1].dir)) < eps) {
            if (dot(H[i].dir, deq[sz - 1].dir) < 0) {
                return {};
            }
            if (outside(H[i], deq[sz - 1].a)) {
                deq.pop_back();
                sz--;
            } else
                continue;
        }
        deq.push_back(H[i]);
        sz++;
    }

    while (sz > 2 and outside(deq[0], Intersection(deq[sz - 1], deq[sz - 2]))) {
        deq.pop_back();
        sz--;
    }
    while (sz > 2 and outside(deq[sz - 1], Intersection(deq[0], deq[1]))) {
        deq.pop_front();
        sz--;
    }
    if (sz < 3)
        return {};
    deq.push_back(deq.front());
    Poly ret;
    rep(i, 0, sz) ret.push_back(Intersection(deq[i], deq[i + 1]));
    return ret;
}

T Area(const Poly &a) {
    T res = 0;
    int n = a.size();
    rep(i, 0, n) res += cross(a[i], a[(i + 1) % n]);
    return fabs(res / 2.);
}
T Area(const Poly &a, const Circle &b) {
    int n = a.size();
    if (n < 3)
        return .0;
    auto rec = [&](auto self, const Circle &c, const Point &p1,
                   const Point &p2) {
        Point va = c.p - p1, vb = c.p - p2;
        T f = cross(va, vb), res = .0;
        if (eq(f, .0))
            return res;
        if (max(abs(va), abs(vb)) < c.r + eps)
            return f;
        if (Dist(Segment(p1, p2), c.p) > c.r - eps)
            return c.r * c.r * arg(vb * conj(va));
        auto u = Intersection(c, Segment(p1, p2));
        Poly sub;
        sub.push_back(p1);
        for (auto &x : u)
            sub.push_back(x);
        sub.push_back(p2);
        rep(i, 0, sub.size() - 1) res += self(self, c, sub[i], sub[i + 1]);
        return res;
    };
    T res = .0;
    rep(i, 0, n) res += rec(rec, b, a[i], a[(i + 1) % n]);
    return fabs(res / 2.);
}
T Area(const Circle &a, const Circle &b) {
    T d = abs(a.p - b.p);
    if (d >= a.r + b.r - eps)
        return .0;
    if (d <= abs(a.r - b.r) + eps) {
        T r = min(a.r, b.r);
        return M_PI * r * r;
    }
    T ath = acos((a.r * a.r + d * d - b.r * b.r) / d / a.r / 2.);
    T res = a.r * a.r * (ath - sin(ath * 2) / 2.);
    T bth = acos((b.r * b.r + d * d - a.r * a.r) / d / b.r / 2.);
    res += b.r * b.r * (bth - sin(bth * 2) / 2.);
    return fabs(res);
}
bool isConvex(const Poly &a) {
    int n = a.size();
    int cur, pre, nxt;
    rep(i, 0, n) {
        pre = (i - 1 + n) % n;
        nxt = (i + 1) % n;
        cur = i;
        if (ccw(a[pre], a[cur], a[nxt]) == -1)
            return 0;
    }
    return 1;
}
int isContained(const Poly &a,
                const Point &b) { // 0:not contain,1:on edge,2:contain

    bool res = 0;
    int n = a.size();
    rep(i, 0, n) {
        Point p = a[i] - b, q = a[(i + 1) % n] - b;
        if (p.Y > q.Y)
            swap(p, q);
        if (p.Y < eps and eps < q.Y and cross(p, q) > eps)
            res ^= 1;
        if (eq(cross(p, q), .0) and dot(p, q) < eps)
            return 1;
    }
    return (res ? 2 : 0);
}
Poly ConvexHull(Poly &a) {
    sort(ALL(a), [](const Point &p, const Point &q) {
        return (eq(p.Y, q.Y) ? p.X < q.X : p.Y < q.Y);
    });
    a.erase(unique(ALL(a)), a.end());
    int n = a.size(), k = 0;
    Poly res(n * 2);
    for (int i = 0; i < n; res[k++] = a[i++]) {
        while (k >= 2 and
               cross(res[k - 1] - res[k - 2], a[i] - res[k - 1]) < eps)
            k--;
    }
    for (int i = n - 2, t = k + 1; i >= 0; res[k++] = a[i--]) {
        while (k >= t and
               cross(res[k - 1] - res[k - 2], a[i] - res[k - 1]) < eps)
            k--;
    }
    res.resize(k - 1);
    return res;
}
T Diam(const Poly &a) {
    int n = a.size();
    int x = 0, y = 0;
    rep(i, 1, n) {
        if (a[i].Y > a[x].Y)
            x = i;
        if (a[i].Y < a[y].Y)
            y = i;
    }
    T res = abs(a[x] - a[y]);
    int i = x, j = y;
    do {
        if (cross(a[(i + 1) % n] - a[i], a[(j + 1) % n] - a[j]) < 0)
            i = (i + 1) % n;
        else
            j = (j + 1) % n;
        chmax(res, abs(a[i] - a[j]));
    } while (i != x or j != y);
    return res;
}
Poly Cut(const Poly &a, const Line &l) {
    int n = a.size();
    Poly res;
    rep(i, 0, n) {
        Point p = a[i], q = a[(i + 1) % n];
        if (ccw(l.a, l.b, p) != -1)
            res.push_back(p);
        if (ccw(l.a, l.b, p) * ccw(l.a, l.b, q) < 0)
            res.push_back(Intersection(Line(p, q), l));
    }
    return res;
}

T Closest(Poly &a) {
    int n = a.size();
    if (n <= 1)
        return 0;
    sort(ALL(a), [&](Point a, Point b) {
        return (eq(a.X, b.X) ? a.Y < b.Y : a.X < b.X);
    });
    Poly buf(n);
    auto rec = [&](auto self, int lb, int rb) -> T {
        if (rb - lb <= 1)
            return (T)INF;
        int mid = (lb + rb) >> 1;
        auto x = a[mid].X;
        T res = min(self(self, lb, mid), self(self, mid, rb));
        inplace_merge(a.begin() + lb, a.begin() + mid, a.begin() + rb,
                      [&](auto p, auto q) { return p.Y < q.Y; });
        int ptr = 0;
        rep(i, lb, rb) {
            if (abs(a[i].X - x) >= res)
                continue;
            rep(j, 0, ptr) {
                auto sub = a[i] - buf[ptr - 1 - j];
                if (sub.Y >= res)
                    break;
                chmin(res, abs(sub));
            }
            buf[ptr++] = a[i];
        }
        return res;
    };
    return rec(rec, 0, n);
}

Circle Incircle(const Point &a, const Point &b, const Point &c) {
    T A = abs(b - c), B = abs(c - a), C = abs(a - b);
    Point p(A * a.X + B * b.X + C * c.X, A * a.Y + B * b.Y + C * c.Y);
    p /= (A + B + C);
    T r = Dist(Line(a, b), p);
    return Circle(p, r);
}
Circle Circumcircle(const Point &a, const Point &b, const Point &c) {
    Line l1((a + b) / 2., (a + b) / 2. + (b - a) * Point(0, 1));
    Line l2((b + c) / 2., (b + c) / 2. + (c - b) * Point(0, 1));
    Point p = Intersection(l1, l2);
    return Circle(p, abs(p - a));
}
Poly tangent(const Point &a, const Circle &b) {
    return Intersection(b, Circle(a, sqrt(norm(b.p - a) - b.r * b.r)));
}
vector<Line> tangent(const Circle &a, const Circle &b) {
    vector<Line> res;
    T d = abs(a.p - b.p);
    if (eq(d, 0.))
        return res;
    Point u = unit(b.p - a.p);
    Point v = u * Point(0, 1);
    for (int t : {-1, 1}) {
        T h = (a.r + b.r * t) / d;
        if (eq(h * h, 1.)) {
            res.push_back(Line(a.p + (h > 0 ? u : -u) * a.r,
                               a.p + (h > 0 ? u : -u) * a.r + v));
        } else if (1 > h * h) {
            Point U = u * h, V = v * sqrt(1 - h * h);
            res.push_back(Line(a.p + (U + V) * a.r, b.p - (U + V) * (b.r * t)));
            res.push_back(Line(a.p + (U - V) * a.r, b.p - (U - V) * (b.r * t)));
        }
    }
    return res;
}

/**
 * @brief Geometry
 */

int main() {
    int N, M;
    cin >> N >> M;
    vector<Poly> V(N);
    vector<Segment> Seg;
    vector<Point> P(M);
    rep(i,0,N) {
        int L;
        cin >> L;
        rep(j,0,L) {
            double PX, PY;
            cin >> PX >> PY;
            V[i].push_back(Point{PX,PY});
        }
        rep(j,0,L) {
            Seg.push_back(Segment(V[i][j],V[i][(j+1)%L]));
        }
    }
    rep(i,0,M) {
        double PX, PY;
        cin >> PX >> PY;
        P[i] = Point(PX,PY);
    }
    vector<Line> L;
    rep(i,0,N) {
        for (Point p : V[i]) {
            rep(j,0,M) {
                L.push_back(Line(p,P[j]));
            }
        }
    }
    int ANS = 0;
    for (Line L1 : L) {
        for (Line L2 : L) {
            if (isParallel(L1,L2)) continue;
            Point Cand = Intersection(L1,L2);
            int COUNT = 0;
            rep(i,0,M) {
                bool flag = true;
                Segment S1(Cand,P[i]);
                for (Segment S2 : Seg) {
                    if (isIntersect(S1,S2)) flag = false;
                }
                if (flag) COUNT++;
            }
            chmax(ANS, COUNT);
        }
    }
    cout << ANS << endl;
}
accuracy: 1
time_ms: 20
memory_kb: 3652
final_rank: 3

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

using ll = long long;
using i64 = long long;
using pll = pair<ll,ll>;
using plll = pair<pll,ll>;
using pii =pair<int,int>;

constexpr ll mod = 1000000007;

int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int dX[4]={1,0,-1,0};
int dY[4]={0,-1,0,1};



//library

#define equals(a,b) (fabs((a)-(b))<EPS)

const double EPS = 1e-10;
const double PI = asinl(1) * 2;

struct Point{
    double x,y;
    Point(){}
    Point(double x,double y):x(x),y(y){}
    Point operator+(Point p) {return Point(x+p.x,y+p.y);}
    Point operator-(Point p) {return Point(x-p.x,y-p.y);}
    Point operator*(double k){return Point(x*k,y*k);}
    Point operator/(double k){return Point(x/k,y/k);}
    double norm(){return x*x+y*y;}
    double abs(){return sqrt(norm());}

    bool operator<(const Point &p) const{
        return x!=p.x?x<p.x:y<p.y;
        //grid-point only
        //return !equals(x,p.x)?x<p.x:!equals(y,p.y)?y<p.y:0;
    }

    bool operator==(const Point &p) const{
        return fabs(x-p.x)<EPS and fabs(y-p.y)<EPS;
    }
};

bool sort_x(Point a,Point b){
    return a.x!=b.x?a.x<b.x:a.y<b.y;
}

bool sort_y(Point a,Point b){
    return a.y!=b.y?a.y<b.y:a.x<b.x;
}

typedef Point Vector;
typedef vector<Point> Polygon;

struct Segment{
    Point p1,p2;
    Segment(){}
    Segment(Point p1, Point p2):p1(p1),p2(p2){}
};
typedef Segment Line;

struct Circle{
    Point c;
    double r;
    Circle(){}
    Circle(Point c,double r):c(c),r(r){}
};

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

Point orth(Point p){return Point(-p.y,p.x);}

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

bool isParallel(Segment s1,Segment s2){
    return equals(cross(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

double arg(Vector p){
    return atan2(p.y,p.x);
}

Vector polar(double a,double r){
    return Point(cos(r)*a,sin(r)*a);
}

// COUNTER CLOCKWISE
static const int CCW_COUNTER_CLOCKWISE = 1;
static const int CCW_CLOCKWISE = -1;
static const int CCW_ONLINE_BACK = 2;
static const int CCW_ONLINE_FRONT = -2;
static const int CCW_ON_SEGMENT = 0;

int ccw(Point p0,Point p1,Point p2){
    Vector a = p1-p0;
    Vector b = p2-p0;
    if(cross(a,b) > EPS) return CCW_COUNTER_CLOCKWISE;
    if(cross(a,b) < -EPS) return CCW_CLOCKWISE;
    if(dot(a,b) < -EPS) return CCW_ONLINE_BACK;
    if(a.norm()<b.norm()) return CCW_ONLINE_FRONT;
    return CCW_ON_SEGMENT;
}

bool intersectSS(Point p1,Point p2,Point p3,Point p4){
    return (ccw(p1,p2,p3)*ccw(p1,p2,p4) <= 0 and
            ccw(p3,p4,p1)*ccw(p3,p4,p2) <= 0 );
}

bool intersectSS(Segment s1,Segment s2){
    return intersectSS(s1.p1,s1.p2,s2.p1,s2.p2);
}

bool intersectPS(Polygon p,Segment l){
    int n=p.size();
    for(int i=0;i<n;++i)
        if(intersectSS(Segment(p[i],p[(i+1)%n]),l)) return 1;
    return 0;
}

double getDistanceLP(Line l,Point p){
    return fabs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1) < 0.0 ) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2) < 0.0 ) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistanceSS(Segment s1,Segment s2){
    if(intersectSS(s1,s2)) return 0.0;
    return min(
            min(getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2)),
            min(getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)));
}

// intercsect of circles
static const int ICC_SEPERATE = 4;
static const int ICC_CIRCUMSCRIBE = 3;
static const int ICC_INTERSECT = 2;
static const int ICC_INSCRIBE = 1;
static const int ICC_CONTAIN = 0;

int intersectCC(Circle c1,Circle c2){
    if(c1.r<c2.r) swap(c1,c2);
    double d=abs(c1.c-c2.c);
    double r=c1.r+c2.r;
    if(equals(d,r)) return ICC_CIRCUMSCRIBE;
    if(d>r) return ICC_SEPERATE;
    if(equals(d+c2.r,c1.r)) return ICC_INSCRIBE;
    if(d+c2.r<c1.r) return ICC_CONTAIN;
    return ICC_INTERSECT;
}

bool intersectSC(Segment s,Circle c){
    return getDistanceSP(s,c.c)<=c.r;
}

int intersectCS(Circle c,Segment s){
    if(norm(project(s,c.c)-c.c)-c.r*c.r>EPS) return 0;
    double d1=abs(c.c-s.p1),d2=abs(c.c-s.p2);
    if(d1<c.r+EPS and d2<c.r+EPS) return 0;
    if((d1<c.r-EPS and d2>c.r+EPS)
       or (d1>c.r+EPS and d2<c.r-EPS)) return 1;
    Point h=project(s,c.c);
    if(dot(s.p1-h,s.p2-h)<0) return 2;
    return 0;
}

Point getCrossPointSS(Segment s1,Segment s2){
    for(int k=0;k<2;++k){
        if(getDistanceSP(s1,s2.p1)<EPS) return s2.p1;
        if(getDistanceSP(s1,s2.p2)<EPS) return s2.p2;
        swap(s1,s2);
    }
    Vector base=s2.p2-s2.p1;
    double d1=fabs(cross(base,s1.p1-s2.p1));
    double d2=fabs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}

Point getCrossPointLL(Line l1,Line l2){
    double a=cross(l1.p2-l1.p1,l2.p2-l2.p1);
    double b=cross(l1.p2-l1.p1,l1.p2-l2.p1);
    if(fabs(a)<EPS and fabs(b)<EPS) return l2.p1;
    return l2.p1+(l2.p2-l2.p1)*(b/a);
}

Polygon getCrossPointCL(Circle c,Line l){
    Polygon ps;
    Point pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    if(equals(getDistanceLP(l,c.c),c.r)){
        ps.emplace_back(pr);
        return ps;
    }
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    ps.emplace_back(pr+e*base);
    ps.emplace_back(pr-e*base);
    return ps;
}

Polygon getCrossPointCS(Circle c,Segment s){
    Line l(s);
    Polygon res=getCrossPointCL(c,l);
    if(intersectCS(c,s)==2) return res;
    if(res.size()>1u){
        if(dot(l.p1-res[0],l.p2-res[0])>0) swap(res[0],res[1]);
        res.pop_back();
    }
    return res;
}


Polygon getCrossPointCC(Circle c1,Circle c2){
    Polygon p(2);
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    p[0]=c1.c+polar(c1.r,t+a);
    p[1]=c1.c+polar(c1.r,t-a);
    return p;
}

// IN:2 ON:1 OUT:0
int contains(Polygon g,Point p){
    int n=g.size();
    bool x=false;
    for(int i=0;i<n;++i){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(fabs(cross(a,b)) < EPS and dot(a,b) < EPS) return 1;
        if(a.y>b.y) swap(a,b);
        if(a.y < EPS and EPS < b.y and cross(a,b) > EPS )
            x = !x;
    }
    return (x?2:0);
}

// BEGIN IGNORE
Polygon andrewScan(Polygon s){
    Polygon u,l;
    if(s.size()<3) return s;
    sort(s.begin(),s.end());
    u.push_back(s[0]);
    u.push_back(s[1]);
    l.push_back(s[s.size()-1]);
    l.push_back(s[s.size()-2]);
    for(int i=2;i<(int)s.size();++i){
        for(int n=u.size();
            n>=2 and ccw(u[n-2],u[n-1],s[i])!=CCW_CLOCKWISE;
            n--){
            u.pop_back();
        }
        u.push_back(s[i]);
    }
    for(int i=s.size()-3;i>=0;i--){
        for(int n=l.size();
            n>=2 and ccw(l[n-2],l[n-1],s[i])!=CCW_CLOCKWISE;
            n--){
            l.pop_back();
        }
        l.push_back(s[i]);
    }
    reverse(l.begin(),l.end());
    for(int i=u.size()-2;i>=1;i--) l.push_back(u[i]);
    return l;
}
// END IGNORE

Polygon convex_hull(Polygon ps){
    int n=ps.size();
    sort(ps.begin(),ps.end(),sort_y);
    int k=0;
    Polygon qs(n*2);
    for(int i=0;i<n;++i){
        while(k>1 and cross(qs[k-1]-qs[k-2],ps[i]-qs[k-1])<0)
            k--;
        qs[k++]=ps[i];
    }
    for(int i=n-2,t=k;i>=0;i--){
        while(k>t and cross(qs[k-1]-qs[k-2],ps[i]-qs[k-1])<0)
            k--;
        qs[k++]=ps[i];
    }
    qs.resize(k-1);
    return qs;
}

double diameter(Polygon s){
    Polygon p=s;
    int n=p.size();
    if(n==2) return abs(p[0]-p[1]);
    int i=0,j=0;
    for(int k=0;k<n;++k){
        if(p[i]<p[k]) i=k;
        if(!(p[j]<p[k])) j=k;
    }
    double res=0;
    int si=i,sj=j;
    while(i!=sj or j!=si){
        res=max(res,abs(p[i]-p[j]));
        if(cross(p[(i+1)%n]-p[i],p[(j+1)%n]-p[j])<0.0){
            i=(i+1)%n;
        }else{
            j=(j+1)%n;
        }
    }
    return res;
}

bool isConvex(Polygon p){
    bool f=1;
    int n=p.size();
    for(int i=0;i<n;++i){
        int t=ccw(p[(i+n-1)%n],p[i],p[(i+1)%n]);
        f&=t!=CCW_CLOCKWISE;
    }
    return f;
}

double area(Polygon s){
    double res=0;
    for(int i=0;i<(int)s.size();++i){
        res+=cross(s[i],s[(i+1)%s.size()])/2.0;
    }
    return res;
}

double area(Circle c1,Circle c2){
    double d=abs(c1.c-c2.c);
    if(c1.r+c2.r<=d+EPS) return 0;
    if(d<=fabs(c1.r-c2.r)){
        double r=min(c1.r,c2.r);
        return PI*r*r;
    }
    double res=0;
    for(int k=0;k<2;++k){
        double rc=(d*d+c1.r*c1.r-c2.r*c2.r)/(2*d*c1.r);
        double th=acosl(rc)*2;
        res+=(th-sinl(th))*c1.r*c1.r/2;
        swap(c1,c2);
    }
    return res;
}

Polygon convexCut(Polygon p,Line l){
    Polygon q;
    for(int i=0;i<(int)p.size();++i){
        Point a=p[i],b=p[(i+1)%p.size()];
        if(ccw(l.p1,l.p2,a)!=-1) q.push_back(a);
        if(ccw(l.p1,l.p2,a)*ccw(l.p1,l.p2,b)<0)
            q.push_back(getCrossPointLL(Line(a,b),l));
    }
    return q;
}

Line bisector(Point p1,Point p2){
    Circle c1=Circle(p1,abs(p1-p2)),c2=Circle(p2,abs(p1-p2));
    Polygon p=getCrossPointCC(c1,c2);
    if(cross(p2-p1,p[0]-p1)>0) swap(p[0],p[1]);
    return Line(p[0],p[1]);
}

Vector translate(Vector v,double theta){
    Vector res;
    res.x=cos(theta)*v.x-sin(theta)*v.y;
    res.y=sin(theta)*v.x+cos(theta)*v.y;
    return res;
}

vector<Line> corner(Line l1,Line l2){
    vector<Line> res;
    if(isParallel(l1,l2)){
        double d=getDistanceLP(l1,l2.p1)/2.0;
        Vector v1=l1.p2-l1.p1;
        v1=v1/v1.abs()*d;
        Point p=l2.p1+translate(v1,90.0*(PI/180.0));
        double d1=getDistanceLP(l1,p);
        double d2=getDistanceLP(l2,p);
        if(fabs(d1-d2)>d){
            p=l2.p1+translate(v1,-90.0*(PI/180.0));
        }
        res.push_back(Line(p,p+v1));
    }else{
        Point p=getCrossPointLL(l1,l2);
        Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
        v1=v1/v1.abs();
        v2=v2/v2.abs();
        res.push_back(Line(p,p+(v1+v2)));
        res.push_back(
                Line(p,p+translate(v1+v2,90.0*(PI/180.0))));
    }
    return res;
}

Polygon tangent(Circle c1,Point p2){
    Circle c2=Circle(p2,sqrt(norm(c1.c-p2)-c1.r*c1.r));
    Polygon p=getCrossPointCC(c1,c2);
    sort(p.begin(),p.end());
    return p;
}

vector<Line> tangent(Circle c1,Circle c2){
    vector<Line> ls;
    if(c1.r<c2.r) swap(c1,c2);
    double g=norm(c1.c-c2.c);
    if(equals(g,0)) return ls;
    Point u=(c2.c-c1.c)/sqrt(g);
    Point v=orth(u);
    for(int s=1;s>=-1;s-=2){
        double h=(c1.r+s*c2.r)/sqrt(g);
        if(equals(1-h*h,0)){
            ls.emplace_back(c1.c+u*c1.r,c1.c+(u+v)*c1.r);
        }else if(1-h*h>0){
            Point uu=u*h,vv=v*sqrt(1-h*h);
            ls.emplace_back(
                    c1.c+(uu+vv)*c1.r,c2.c-(uu+vv)*c2.r*s);
            ls.emplace_back(
                    c1.c+(uu-vv)*c1.r,c2.c-(uu-vv)*c2.r*s);
        }
    }

    return ls;
}

double closest_pair(Polygon &a,int l=0,int r=-1){
    if(r<0){
        r=a.size();
        sort(a.begin(),a.end(),sort_x);
    }
    if(r-l<=1) return abs(a[0]-a[1]);
    int m=(l+r)>>1;
    double x=a[m].x;
    double d=min(closest_pair(a,l,m),closest_pair(a,m,r));
    inplace_merge(a.begin()+l,a.begin()+m,a.begin()+r,sort_y);

    Polygon b;
    for(int i=l;i<r;++i){
        if(fabs(a[i].x-x)>=d) continue;
        for(int j=0;j<(int)b.size();++j){
            double dy=a[i].y-next(b.rbegin(),j)->y;
            if(dy>=d) break;
            d=min(d,abs(a[i]-*next(b.rbegin(),j)));
        }
        b.emplace_back(a[i]);
    }
    return d;
}

vector<vector<int>>
segmentArrangement(vector<Segment> &ss, Polygon &ps){
    int n=ss.size();
    for(int i=0;i<n;++i){
        ps.emplace_back(ss[i].p1);
        ps.emplace_back(ss[i].p2);
        for(int j=i+1;j<n;++j)
            if(intersectSS(ss[i],ss[j]))
                ps.emplace_back(getCrossPointSS(ss[i],ss[j]));
    }
    sort(ps.begin(),ps.end());
    ps.erase(unique(ps.begin(),ps.end()),ps.end());

    vector<vector<int> > G(ps.size());
    for(int i=0;i<n;++i){
        vector<pair<double,int> > ls;
        for(int j=0;j<(int)ps.size();++j)
            if(getDistanceSP(ss[i],ps[j])<EPS)
                ls.emplace_back(make_pair(norm(ss[i].p1-ps[j]),j));

        sort(ls.begin(),ls.end());
        for(int j=0;j+1<(int)ls.size();++j){
            int a=ls[j].second,b=ls[j+1].second;
            G[a].emplace_back(b);
            G[b].emplace_back(a);
        }
    }
    for(auto &v:G){
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
    }
    return G;
}

struct EndPoint{
    Point p;
    int seg,st;
    EndPoint(){}
    EndPoint(Point p,int seg,int st):p(p),seg(seg),st(st){}
    bool operator<(const EndPoint &ep)const{
        if(p.y==ep.p.y) return st<ep.st;
        return p.y<ep.p.y;
    }
};

int manhattan_intersection(
        vector<Segment> ss,const int INF){
    const int BTM = 0;
    const int LFT = 1;
    const int RGH = 2;
    const int TOP = 3;

    int n=ss.size();
    vector<EndPoint> ep;
    for(int i=0;i<n;++i){
        if(ss[i].p1.y==ss[i].p2.y){
            if(ss[i].p1.x>ss[i].p2.x) swap(ss[i].p1,ss[i].p2);
            ep.emplace_back(ss[i].p1,i,LFT);
            ep.emplace_back(ss[i].p2,i,RGH);
        }else{
            if(ss[i].p1.y>ss[i].p2.y) swap(ss[i].p1,ss[i].p2);
            ep.emplace_back(ss[i].p1,i,BTM);
            ep.emplace_back(ss[i].p2,i,TOP);
        }
    }
    sort(ep.begin(),ep.end());

    set<int> bt;
    bt.insert(INF);

    int cnt=0;
    for(int i=0;i<n*2;++i){
        if(ep[i].st==TOP){
            bt.erase(ep[i].p.x);
        }else if(ep[i].st==BTM){
            bt.emplace(ep[i].p.x);
        }else if(ep[i].st==LFT){
            auto b=bt.lower_bound(ss[ep[i].seg].p1.x);
            auto e=bt.upper_bound(ss[ep[i].seg].p2.x);
            cnt+=distance(b,e);
        }
    }

    return cnt;
}

double area(Polygon ps,Circle c){
    if(ps.size()<3u) return 0;
    function<double(Circle, Point, Point)> dfs=
            [&](Circle c,Point a,Point b){
                Vector va=c.c-a,vb=c.c-b;
                double f=cross(va,vb),res=0;
                if(equals(f,0.0)) return res;
                if(max(abs(va),abs(vb))<c.r+EPS) return f;
                Vector d(dot(va,vb),cross(va,vb));
                if(getDistanceSP(Segment(a,b),c.c)>c.r-EPS)
                    return c.r*c.r*atan2(d.y,d.x);
                auto u=getCrossPointCS(c,Segment(a,b));
                if(u.empty()) return res;
                if(u.size()>1u and dot(u[1]-u[0],a-u[0])>0)
                    swap(u[0],u[1]);
                u.emplace(u.begin(),a);
                u.emplace_back(b);
                for(int i=1;i<(int)u.size();++i)
                    res+=dfs(c,u[i-1],u[i]);
                return res;
            };
    double res=0;
    for(int i=0;i<(int)ps.size();++i)
        res+=dfs(c,ps[i],ps[(i+1)%ps.size()]);
    return res/2;
}
//end




using Graph =vector<vector<int>>;

int main(){
    int n,m;
    cin>>n>>m;
    vector<Segment> S;
    
    for (int i=0; i<n; i++){
        int l;
        cin>>l;
        vector<pii> P(l);
        for (int i=0; i<l; i++){
            cin>>P[i].first>>P[i].second;
        }
        for (int i=0; i<l; i++){
            Point p1(P[i].first,P[i].second);
            Point p2(P[(i+1)%l].first,P[(i+1)%l].second);
            S.push_back(Segment(p1,p2));
        }

    }
    vector<pii>People(m);
    for (int i=0; i<m; i++){
        cin>>People[i].first>>People[i].second;
    }

    int h=500;
    int ans=0;
    for (int x=-h; x<=h; x++ ){
        for (int y=-h; y<=h; y++){
            Point p0(x,y);
            int sans=0;
            for (int i=0; i<m; i++){
                Point pp(People[i].first,People[i].second);
                bool f=true;
                Segment s={p0,pp};
                for (auto t: S){
                    if (intersectSS(s,t)){
                        auto p3=getCrossPointSS(s,t);
                        if (p3==t.p1 || p3==t.p2 || p3==s.p1 || p3==s.p2)continue;
                        f=false;
                        break;
                    }
                }
                if (f)sans++;
                
            }
            ans=max(ans,sans);
        }
    }
    cout<<ans<<endl;



}
accuracy: 1
time_ms: 920
memory_kb: 3492
final_rank: 10

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

using ll = long long;
using i64 = long long;
using pll = pair<ll,ll>;
using plll = pair<pll,ll>;
using pii =pair<int,int>;

constexpr ll mod = 1000000007;

int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int dX[4]={1,0,-1,0};
int dY[4]={0,-1,0,1};



//library

#define equals(a,b) (fabs((a)-(b))<EPS)

const double EPS = 1e-10;
const double PI = asinl(1) * 2;

struct Point{
    double x,y;
    Point(){}
    Point(double x,double y):x(x),y(y){}
    Point operator+(Point p) {return Point(x+p.x,y+p.y);}
    Point operator-(Point p) {return Point(x-p.x,y-p.y);}
    Point operator*(double k){return Point(x*k,y*k);}
    Point operator/(double k){return Point(x/k,y/k);}
    double norm(){return x*x+y*y;}
    double abs(){return sqrt(norm());}

    bool operator<(const Point &p) const{
        return x!=p.x?x<p.x:y<p.y;
        //grid-point only
        //return !equals(x,p.x)?x<p.x:!equals(y,p.y)?y<p.y:0;
    }

    bool operator==(const Point &p) const{
        return fabs(x-p.x)<EPS and fabs(y-p.y)<EPS;
    }
};

bool sort_x(Point a,Point b){
    return a.x!=b.x?a.x<b.x:a.y<b.y;
}

bool sort_y(Point a,Point b){
    return a.y!=b.y?a.y<b.y:a.x<b.x;
}

typedef Point Vector;
typedef vector<Point> Polygon;

struct Segment{
    Point p1,p2;
    Segment(){}
    Segment(Point p1, Point p2):p1(p1),p2(p2){}
};
typedef Segment Line;

struct Circle{
    Point c;
    double r;
    Circle(){}
    Circle(Point c,double r):c(c),r(r){}
};

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

Point orth(Point p){return Point(-p.y,p.x);}

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

bool isParallel(Segment s1,Segment s2){
    return equals(cross(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

double arg(Vector p){
    return atan2(p.y,p.x);
}

Vector polar(double a,double r){
    return Point(cos(r)*a,sin(r)*a);
}

// COUNTER CLOCKWISE
static const int CCW_COUNTER_CLOCKWISE = 1;
static const int CCW_CLOCKWISE = -1;
static const int CCW_ONLINE_BACK = 2;
static const int CCW_ONLINE_FRONT = -2;
static const int CCW_ON_SEGMENT = 0;

int ccw(Point p0,Point p1,Point p2){
    Vector a = p1-p0;
    Vector b = p2-p0;
    if(cross(a,b) > EPS) return CCW_COUNTER_CLOCKWISE;
    if(cross(a,b) < -EPS) return CCW_CLOCKWISE;
    if(dot(a,b) < -EPS) return CCW_ONLINE_BACK;
    if(a.norm()<b.norm()) return CCW_ONLINE_FRONT;
    return CCW_ON_SEGMENT;
}

bool intersectSS(Point p1,Point p2,Point p3,Point p4){
    return (ccw(p1,p2,p3)*ccw(p1,p2,p4) <= 0 and
            ccw(p3,p4,p1)*ccw(p3,p4,p2) <= 0 );
}

bool intersectSS(Segment s1,Segment s2){
    return intersectSS(s1.p1,s1.p2,s2.p1,s2.p2);
}

bool intersectPS(Polygon p,Segment l){
    int n=p.size();
    for(int i=0;i<n;++i)
        if(intersectSS(Segment(p[i],p[(i+1)%n]),l)) return 1;
    return 0;
}

double getDistanceLP(Line l,Point p){
    return fabs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1) < 0.0 ) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2) < 0.0 ) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistanceSS(Segment s1,Segment s2){
    if(intersectSS(s1,s2)) return 0.0;
    return min(
            min(getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2)),
            min(getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)));
}

// intercsect of circles
static const int ICC_SEPERATE = 4;
static const int ICC_CIRCUMSCRIBE = 3;
static const int ICC_INTERSECT = 2;
static const int ICC_INSCRIBE = 1;
static const int ICC_CONTAIN = 0;

int intersectCC(Circle c1,Circle c2){
    if(c1.r<c2.r) swap(c1,c2);
    double d=abs(c1.c-c2.c);
    double r=c1.r+c2.r;
    if(equals(d,r)) return ICC_CIRCUMSCRIBE;
    if(d>r) return ICC_SEPERATE;
    if(equals(d+c2.r,c1.r)) return ICC_INSCRIBE;
    if(d+c2.r<c1.r) return ICC_CONTAIN;
    return ICC_INTERSECT;
}

bool intersectSC(Segment s,Circle c){
    return getDistanceSP(s,c.c)<=c.r;
}

int intersectCS(Circle c,Segment s){
    if(norm(project(s,c.c)-c.c)-c.r*c.r>EPS) return 0;
    double d1=abs(c.c-s.p1),d2=abs(c.c-s.p2);
    if(d1<c.r+EPS and d2<c.r+EPS) return 0;
    if((d1<c.r-EPS and d2>c.r+EPS)
       or (d1>c.r+EPS and d2<c.r-EPS)) return 1;
    Point h=project(s,c.c);
    if(dot(s.p1-h,s.p2-h)<0) return 2;
    return 0;
}

Point getCrossPointSS(Segment s1,Segment s2){
    for(int k=0;k<2;++k){
        if(getDistanceSP(s1,s2.p1)<EPS) return s2.p1;
        if(getDistanceSP(s1,s2.p2)<EPS) return s2.p2;
        swap(s1,s2);
    }
    Vector base=s2.p2-s2.p1;
    double d1=fabs(cross(base,s1.p1-s2.p1));
    double d2=fabs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}

Point getCrossPointLL(Line l1,Line l2){
    double a=cross(l1.p2-l1.p1,l2.p2-l2.p1);
    double b=cross(l1.p2-l1.p1,l1.p2-l2.p1);
    if(fabs(a)<EPS and fabs(b)<EPS) return l2.p1;
    return l2.p1+(l2.p2-l2.p1)*(b/a);
}

Polygon getCrossPointCL(Circle c,Line l){
    Polygon ps;
    Point pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    if(equals(getDistanceLP(l,c.c),c.r)){
        ps.emplace_back(pr);
        return ps;
    }
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    ps.emplace_back(pr+e*base);
    ps.emplace_back(pr-e*base);
    return ps;
}

Polygon getCrossPointCS(Circle c,Segment s){
    Line l(s);
    Polygon res=getCrossPointCL(c,l);
    if(intersectCS(c,s)==2) return res;
    if(res.size()>1u){
        if(dot(l.p1-res[0],l.p2-res[0])>0) swap(res[0],res[1]);
        res.pop_back();
    }
    return res;
}


Polygon getCrossPointCC(Circle c1,Circle c2){
    Polygon p(2);
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    p[0]=c1.c+polar(c1.r,t+a);
    p[1]=c1.c+polar(c1.r,t-a);
    return p;
}

// IN:2 ON:1 OUT:0
int contains(Polygon g,Point p){
    int n=g.size();
    bool x=false;
    for(int i=0;i<n;++i){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(fabs(cross(a,b)) < EPS and dot(a,b) < EPS) return 1;
        if(a.y>b.y) swap(a,b);
        if(a.y < EPS and EPS < b.y and cross(a,b) > EPS )
            x = !x;
    }
    return (x?2:0);
}

// BEGIN IGNORE
Polygon andrewScan(Polygon s){
    Polygon u,l;
    if(s.size()<3) return s;
    sort(s.begin(),s.end());
    u.push_back(s[0]);
    u.push_back(s[1]);
    l.push_back(s[s.size()-1]);
    l.push_back(s[s.size()-2]);
    for(int i=2;i<(int)s.size();++i){
        for(int n=u.size();
            n>=2 and ccw(u[n-2],u[n-1],s[i])!=CCW_CLOCKWISE;
            n--){
            u.pop_back();
        }
        u.push_back(s[i]);
    }
    for(int i=s.size()-3;i>=0;i--){
        for(int n=l.size();
            n>=2 and ccw(l[n-2],l[n-1],s[i])!=CCW_CLOCKWISE;
            n--){
            l.pop_back();
        }
        l.push_back(s[i]);
    }
    reverse(l.begin(),l.end());
    for(int i=u.size()-2;i>=1;i--) l.push_back(u[i]);
    return l;
}
// END IGNORE

Polygon convex_hull(Polygon ps){
    int n=ps.size();
    sort(ps.begin(),ps.end(),sort_y);
    int k=0;
    Polygon qs(n*2);
    for(int i=0;i<n;++i){
        while(k>1 and cross(qs[k-1]-qs[k-2],ps[i]-qs[k-1])<0)
            k--;
        qs[k++]=ps[i];
    }
    for(int i=n-2,t=k;i>=0;i--){
        while(k>t and cross(qs[k-1]-qs[k-2],ps[i]-qs[k-1])<0)
            k--;
        qs[k++]=ps[i];
    }
    qs.resize(k-1);
    return qs;
}

double diameter(Polygon s){
    Polygon p=s;
    int n=p.size();
    if(n==2) return abs(p[0]-p[1]);
    int i=0,j=0;
    for(int k=0;k<n;++k){
        if(p[i]<p[k]) i=k;
        if(!(p[j]<p[k])) j=k;
    }
    double res=0;
    int si=i,sj=j;
    while(i!=sj or j!=si){
        res=max(res,abs(p[i]-p[j]));
        if(cross(p[(i+1)%n]-p[i],p[(j+1)%n]-p[j])<0.0){
            i=(i+1)%n;
        }else{
            j=(j+1)%n;
        }
    }
    return res;
}

bool isConvex(Polygon p){
    bool f=1;
    int n=p.size();
    for(int i=0;i<n;++i){
        int t=ccw(p[(i+n-1)%n],p[i],p[(i+1)%n]);
        f&=t!=CCW_CLOCKWISE;
    }
    return f;
}

double area(Polygon s){
    double res=0;
    for(int i=0;i<(int)s.size();++i){
        res+=cross(s[i],s[(i+1)%s.size()])/2.0;
    }
    return res;
}

double area(Circle c1,Circle c2){
    double d=abs(c1.c-c2.c);
    if(c1.r+c2.r<=d+EPS) return 0;
    if(d<=fabs(c1.r-c2.r)){
        double r=min(c1.r,c2.r);
        return PI*r*r;
    }
    double res=0;
    for(int k=0;k<2;++k){
        double rc=(d*d+c1.r*c1.r-c2.r*c2.r)/(2*d*c1.r);
        double th=acosl(rc)*2;
        res+=(th-sinl(th))*c1.r*c1.r/2;
        swap(c1,c2);
    }
    return res;
}

Polygon convexCut(Polygon p,Line l){
    Polygon q;
    for(int i=0;i<(int)p.size();++i){
        Point a=p[i],b=p[(i+1)%p.size()];
        if(ccw(l.p1,l.p2,a)!=-1) q.push_back(a);
        if(ccw(l.p1,l.p2,a)*ccw(l.p1,l.p2,b)<0)
            q.push_back(getCrossPointLL(Line(a,b),l));
    }
    return q;
}

Line bisector(Point p1,Point p2){
    Circle c1=Circle(p1,abs(p1-p2)),c2=Circle(p2,abs(p1-p2));
    Polygon p=getCrossPointCC(c1,c2);
    if(cross(p2-p1,p[0]-p1)>0) swap(p[0],p[1]);
    return Line(p[0],p[1]);
}

Vector translate(Vector v,double theta){
    Vector res;
    res.x=cos(theta)*v.x-sin(theta)*v.y;
    res.y=sin(theta)*v.x+cos(theta)*v.y;
    return res;
}

vector<Line> corner(Line l1,Line l2){
    vector<Line> res;
    if(isParallel(l1,l2)){
        double d=getDistanceLP(l1,l2.p1)/2.0;
        Vector v1=l1.p2-l1.p1;
        v1=v1/v1.abs()*d;
        Point p=l2.p1+translate(v1,90.0*(PI/180.0));
        double d1=getDistanceLP(l1,p);
        double d2=getDistanceLP(l2,p);
        if(fabs(d1-d2)>d){
            p=l2.p1+translate(v1,-90.0*(PI/180.0));
        }
        res.push_back(Line(p,p+v1));
    }else{
        Point p=getCrossPointLL(l1,l2);
        Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
        v1=v1/v1.abs();
        v2=v2/v2.abs();
        res.push_back(Line(p,p+(v1+v2)));
        res.push_back(
                Line(p,p+translate(v1+v2,90.0*(PI/180.0))));
    }
    return res;
}

Polygon tangent(Circle c1,Point p2){
    Circle c2=Circle(p2,sqrt(norm(c1.c-p2)-c1.r*c1.r));
    Polygon p=getCrossPointCC(c1,c2);
    sort(p.begin(),p.end());
    return p;
}

vector<Line> tangent(Circle c1,Circle c2){
    vector<Line> ls;
    if(c1.r<c2.r) swap(c1,c2);
    double g=norm(c1.c-c2.c);
    if(equals(g,0)) return ls;
    Point u=(c2.c-c1.c)/sqrt(g);
    Point v=orth(u);
    for(int s=1;s>=-1;s-=2){
        double h=(c1.r+s*c2.r)/sqrt(g);
        if(equals(1-h*h,0)){
            ls.emplace_back(c1.c+u*c1.r,c1.c+(u+v)*c1.r);
        }else if(1-h*h>0){
            Point uu=u*h,vv=v*sqrt(1-h*h);
            ls.emplace_back(
                    c1.c+(uu+vv)*c1.r,c2.c-(uu+vv)*c2.r*s);
            ls.emplace_back(
                    c1.c+(uu-vv)*c1.r,c2.c-(uu-vv)*c2.r*s);
        }
    }

    return ls;
}

double closest_pair(Polygon &a,int l=0,int r=-1){
    if(r<0){
        r=a.size();
        sort(a.begin(),a.end(),sort_x);
    }
    if(r-l<=1) return abs(a[0]-a[1]);
    int m=(l+r)>>1;
    double x=a[m].x;
    double d=min(closest_pair(a,l,m),closest_pair(a,m,r));
    inplace_merge(a.begin()+l,a.begin()+m,a.begin()+r,sort_y);

    Polygon b;
    for(int i=l;i<r;++i){
        if(fabs(a[i].x-x)>=d) continue;
        for(int j=0;j<(int)b.size();++j){
            double dy=a[i].y-next(b.rbegin(),j)->y;
            if(dy>=d) break;
            d=min(d,abs(a[i]-*next(b.rbegin(),j)));
        }
        b.emplace_back(a[i]);
    }
    return d;
}

vector<vector<int>>
segmentArrangement(vector<Segment> &ss, Polygon &ps){
    int n=ss.size();
    for(int i=0;i<n;++i){
        ps.emplace_back(ss[i].p1);
        ps.emplace_back(ss[i].p2);
        for(int j=i+1;j<n;++j)
            if(intersectSS(ss[i],ss[j]))
                ps.emplace_back(getCrossPointSS(ss[i],ss[j]));
    }
    sort(ps.begin(),ps.end());
    ps.erase(unique(ps.begin(),ps.end()),ps.end());

    vector<vector<int> > G(ps.size());
    for(int i=0;i<n;++i){
        vector<pair<double,int> > ls;
        for(int j=0;j<(int)ps.size();++j)
            if(getDistanceSP(ss[i],ps[j])<EPS)
                ls.emplace_back(make_pair(norm(ss[i].p1-ps[j]),j));

        sort(ls.begin(),ls.end());
        for(int j=0;j+1<(int)ls.size();++j){
            int a=ls[j].second,b=ls[j+1].second;
            G[a].emplace_back(b);
            G[b].emplace_back(a);
        }
    }
    for(auto &v:G){
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
    }
    return G;
}

struct EndPoint{
    Point p;
    int seg,st;
    EndPoint(){}
    EndPoint(Point p,int seg,int st):p(p),seg(seg),st(st){}
    bool operator<(const EndPoint &ep)const{
        if(p.y==ep.p.y) return st<ep.st;
        return p.y<ep.p.y;
    }
};

int manhattan_intersection(
        vector<Segment> ss,const int INF){
    const int BTM = 0;
    const int LFT = 1;
    const int RGH = 2;
    const int TOP = 3;

    int n=ss.size();
    vector<EndPoint> ep;
    for(int i=0;i<n;++i){
        if(ss[i].p1.y==ss[i].p2.y){
            if(ss[i].p1.x>ss[i].p2.x) swap(ss[i].p1,ss[i].p2);
            ep.emplace_back(ss[i].p1,i,LFT);
            ep.emplace_back(ss[i].p2,i,RGH);
        }else{
            if(ss[i].p1.y>ss[i].p2.y) swap(ss[i].p1,ss[i].p2);
            ep.emplace_back(ss[i].p1,i,BTM);
            ep.emplace_back(ss[i].p2,i,TOP);
        }
    }
    sort(ep.begin(),ep.end());

    set<int> bt;
    bt.insert(INF);

    int cnt=0;
    for(int i=0;i<n*2;++i){
        if(ep[i].st==TOP){
            bt.erase(ep[i].p.x);
        }else if(ep[i].st==BTM){
            bt.emplace(ep[i].p.x);
        }else if(ep[i].st==LFT){
            auto b=bt.lower_bound(ss[ep[i].seg].p1.x);
            auto e=bt.upper_bound(ss[ep[i].seg].p2.x);
            cnt+=distance(b,e);
        }
    }

    return cnt;
}

double area(Polygon ps,Circle c){
    if(ps.size()<3u) return 0;
    function<double(Circle, Point, Point)> dfs=
            [&](Circle c,Point a,Point b){
                Vector va=c.c-a,vb=c.c-b;
                double f=cross(va,vb),res=0;
                if(equals(f,0.0)) return res;
                if(max(abs(va),abs(vb))<c.r+EPS) return f;
                Vector d(dot(va,vb),cross(va,vb));
                if(getDistanceSP(Segment(a,b),c.c)>c.r-EPS)
                    return c.r*c.r*atan2(d.y,d.x);
                auto u=getCrossPointCS(c,Segment(a,b));
                if(u.empty()) return res;
                if(u.size()>1u and dot(u[1]-u[0],a-u[0])>0)
                    swap(u[0],u[1]);
                u.emplace(u.begin(),a);
                u.emplace_back(b);
                for(int i=1;i<(int)u.size();++i)
                    res+=dfs(c,u[i-1],u[i]);
                return res;
            };
    double res=0;
    for(int i=0;i<(int)ps.size();++i)
        res+=dfs(c,ps[i],ps[(i+1)%ps.size()]);
    return res/2;
}
//end




using Graph =vector<vector<int>>;

int main(){
    int n,m;
    cin>>n>>m;
    vector<Segment> S;
    
    for (int i=0; i<n; i++){
        int l;
        cin>>l;
        vector<pii> P(l);
        for (int i=0; i<l; i++){
            cin>>P[i].first>>P[i].second;
        }
        for (int i=0; i<l; i++){
            Point p1(P[i].first,P[i].second);
            Point p2(P[(i+1)%l].first,P[(i+1)%l].second);
            S.push_back(Segment(p1,p2));
        }

    }
    vector<pii>People(m);
    for (int i=0; i<m; i++){
        cin>>People[i].first>>People[i].second;
    }

    int h=500;
    int ans=0;
    for (int x=-h; x<=h; x++ ){
        for (int y=-h; y<=h; y++){
            Point p0(x,y);
            int sans=0;
            for (int i=0; i<m; i++){
                Point pp(People[i].first,People[i].second);
                bool f=true;
                Segment s={p0,pp};
                for (auto t: S){
                    if (intersectSS(s,t)){
                        auto p3=getCrossPointSS(s,t);
                        if (p3==t.p1 || p3==t.p2)continue;
                        f=false;
                        break;
                    }
                }
                if (f)sans++;
                
            }
            ans=max(ans,sans);
        }
    }
    cout<<ans<<endl;



}
accuracy: 0.08695652173913043
time_ms: 170
memory_kb: 3412
final_rank: 17

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

using ll = long long;
using i64 = long long;
using pll = pair<ll,ll>;
using plll = pair<pll,ll>;
using pii =pair<int,int>;

constexpr ll mod = 1000000007;

int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int dX[4]={1,0,-1,0};
int dY[4]={0,-1,0,1};



//library

#define equals(a,b) (fabs((a)-(b))<EPS)

const double EPS = 1e-10;
const double PI = asinl(1) * 2;

struct Point{
    double x,y;
    Point(){}
    Point(double x,double y):x(x),y(y){}
    Point operator+(Point p) {return Point(x+p.x,y+p.y);}
    Point operator-(Point p) {return Point(x-p.x,y-p.y);}
    Point operator*(double k){return Point(x*k,y*k);}
    Point operator/(double k){return Point(x/k,y/k);}
    double norm(){return x*x+y*y;}
    double abs(){return sqrt(norm());}

    bool operator<(const Point &p) const{
        return x!=p.x?x<p.x:y<p.y;
        //grid-point only
        //return !equals(x,p.x)?x<p.x:!equals(y,p.y)?y<p.y:0;
    }

    bool operator==(const Point &p) const{
        return fabs(x-p.x)<EPS and fabs(y-p.y)<EPS;
    }
};

bool sort_x(Point a,Point b){
    return a.x!=b.x?a.x<b.x:a.y<b.y;
}

bool sort_y(Point a,Point b){
    return a.y!=b.y?a.y<b.y:a.x<b.x;
}

typedef Point Vector;
typedef vector<Point> Polygon;

struct Segment{
    Point p1,p2;
    Segment(){}
    Segment(Point p1, Point p2):p1(p1),p2(p2){}
};
typedef Segment Line;

struct Circle{
    Point c;
    double r;
    Circle(){}
    Circle(Point c,double r):c(c),r(r){}
};

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

Point orth(Point p){return Point(-p.y,p.x);}

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

bool isParallel(Segment s1,Segment s2){
    return equals(cross(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

double arg(Vector p){
    return atan2(p.y,p.x);
}

Vector polar(double a,double r){
    return Point(cos(r)*a,sin(r)*a);
}

// COUNTER CLOCKWISE
static const int CCW_COUNTER_CLOCKWISE = 1;
static const int CCW_CLOCKWISE = -1;
static const int CCW_ONLINE_BACK = 2;
static const int CCW_ONLINE_FRONT = -2;
static const int CCW_ON_SEGMENT = 0;

int ccw(Point p0,Point p1,Point p2){
    Vector a = p1-p0;
    Vector b = p2-p0;
    if(cross(a,b) > EPS) return CCW_COUNTER_CLOCKWISE;
    if(cross(a,b) < -EPS) return CCW_CLOCKWISE;
    if(dot(a,b) < -EPS) return CCW_ONLINE_BACK;
    if(a.norm()<b.norm()) return CCW_ONLINE_FRONT;
    return CCW_ON_SEGMENT;
}

bool intersectSS(Point p1,Point p2,Point p3,Point p4){
    return (ccw(p1,p2,p3)*ccw(p1,p2,p4) <= 0 and
            ccw(p3,p4,p1)*ccw(p3,p4,p2) <= 0 );
}

bool intersectSS(Segment s1,Segment s2){
    return intersectSS(s1.p1,s1.p2,s2.p1,s2.p2);
}

bool intersectPS(Polygon p,Segment l){
    int n=p.size();
    for(int i=0;i<n;++i)
        if(intersectSS(Segment(p[i],p[(i+1)%n]),l)) return 1;
    return 0;
}

double getDistanceLP(Line l,Point p){
    return fabs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1) < 0.0 ) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2) < 0.0 ) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistanceSS(Segment s1,Segment s2){
    if(intersectSS(s1,s2)) return 0.0;
    return min(
            min(getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2)),
            min(getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)));
}

// intercsect of circles
static const int ICC_SEPERATE = 4;
static const int ICC_CIRCUMSCRIBE = 3;
static const int ICC_INTERSECT = 2;
static const int ICC_INSCRIBE = 1;
static const int ICC_CONTAIN = 0;

int intersectCC(Circle c1,Circle c2){
    if(c1.r<c2.r) swap(c1,c2);
    double d=abs(c1.c-c2.c);
    double r=c1.r+c2.r;
    if(equals(d,r)) return ICC_CIRCUMSCRIBE;
    if(d>r) return ICC_SEPERATE;
    if(equals(d+c2.r,c1.r)) return ICC_INSCRIBE;
    if(d+c2.r<c1.r) return ICC_CONTAIN;
    return ICC_INTERSECT;
}

bool intersectSC(Segment s,Circle c){
    return getDistanceSP(s,c.c)<=c.r;
}

int intersectCS(Circle c,Segment s){
    if(norm(project(s,c.c)-c.c)-c.r*c.r>EPS) return 0;
    double d1=abs(c.c-s.p1),d2=abs(c.c-s.p2);
    if(d1<c.r+EPS and d2<c.r+EPS) return 0;
    if((d1<c.r-EPS and d2>c.r+EPS)
       or (d1>c.r+EPS and d2<c.r-EPS)) return 1;
    Point h=project(s,c.c);
    if(dot(s.p1-h,s.p2-h)<0) return 2;
    return 0;
}

Point getCrossPointSS(Segment s1,Segment s2){
    for(int k=0;k<2;++k){
        if(getDistanceSP(s1,s2.p1)<EPS) return s2.p1;
        if(getDistanceSP(s1,s2.p2)<EPS) return s2.p2;
        swap(s1,s2);
    }
    Vector base=s2.p2-s2.p1;
    double d1=fabs(cross(base,s1.p1-s2.p1));
    double d2=fabs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}

Point getCrossPointLL(Line l1,Line l2){
    double a=cross(l1.p2-l1.p1,l2.p2-l2.p1);
    double b=cross(l1.p2-l1.p1,l1.p2-l2.p1);
    if(fabs(a)<EPS and fabs(b)<EPS) return l2.p1;
    return l2.p1+(l2.p2-l2.p1)*(b/a);
}

Polygon getCrossPointCL(Circle c,Line l){
    Polygon ps;
    Point pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    if(equals(getDistanceLP(l,c.c),c.r)){
        ps.emplace_back(pr);
        return ps;
    }
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    ps.emplace_back(pr+e*base);
    ps.emplace_back(pr-e*base);
    return ps;
}

Polygon getCrossPointCS(Circle c,Segment s){
    Line l(s);
    Polygon res=getCrossPointCL(c,l);
    if(intersectCS(c,s)==2) return res;
    if(res.size()>1u){
        if(dot(l.p1-res[0],l.p2-res[0])>0) swap(res[0],res[1]);
        res.pop_back();
    }
    return res;
}


Polygon getCrossPointCC(Circle c1,Circle c2){
    Polygon p(2);
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    p[0]=c1.c+polar(c1.r,t+a);
    p[1]=c1.c+polar(c1.r,t-a);
    return p;
}

// IN:2 ON:1 OUT:0
int contains(Polygon g,Point p){
    int n=g.size();
    bool x=false;
    for(int i=0;i<n;++i){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(fabs(cross(a,b)) < EPS and dot(a,b) < EPS) return 1;
        if(a.y>b.y) swap(a,b);
        if(a.y < EPS and EPS < b.y and cross(a,b) > EPS )
            x = !x;
    }
    return (x?2:0);
}

// BEGIN IGNORE
Polygon andrewScan(Polygon s){
    Polygon u,l;
    if(s.size()<3) return s;
    sort(s.begin(),s.end());
    u.push_back(s[0]);
    u.push_back(s[1]);
    l.push_back(s[s.size()-1]);
    l.push_back(s[s.size()-2]);
    for(int i=2;i<(int)s.size();++i){
        for(int n=u.size();
            n>=2 and ccw(u[n-2],u[n-1],s[i])!=CCW_CLOCKWISE;
            n--){
            u.pop_back();
        }
        u.push_back(s[i]);
    }
    for(int i=s.size()-3;i>=0;i--){
        for(int n=l.size();
            n>=2 and ccw(l[n-2],l[n-1],s[i])!=CCW_CLOCKWISE;
            n--){
            l.pop_back();
        }
        l.push_back(s[i]);
    }
    reverse(l.begin(),l.end());
    for(int i=u.size()-2;i>=1;i--) l.push_back(u[i]);
    return l;
}
// END IGNORE

Polygon convex_hull(Polygon ps){
    int n=ps.size();
    sort(ps.begin(),ps.end(),sort_y);
    int k=0;
    Polygon qs(n*2);
    for(int i=0;i<n;++i){
        while(k>1 and cross(qs[k-1]-qs[k-2],ps[i]-qs[k-1])<0)
            k--;
        qs[k++]=ps[i];
    }
    for(int i=n-2,t=k;i>=0;i--){
        while(k>t and cross(qs[k-1]-qs[k-2],ps[i]-qs[k-1])<0)
            k--;
        qs[k++]=ps[i];
    }
    qs.resize(k-1);
    return qs;
}

double diameter(Polygon s){
    Polygon p=s;
    int n=p.size();
    if(n==2) return abs(p[0]-p[1]);
    int i=0,j=0;
    for(int k=0;k<n;++k){
        if(p[i]<p[k]) i=k;
        if(!(p[j]<p[k])) j=k;
    }
    double res=0;
    int si=i,sj=j;
    while(i!=sj or j!=si){
        res=max(res,abs(p[i]-p[j]));
        if(cross(p[(i+1)%n]-p[i],p[(j+1)%n]-p[j])<0.0){
            i=(i+1)%n;
        }else{
            j=(j+1)%n;
        }
    }
    return res;
}

bool isConvex(Polygon p){
    bool f=1;
    int n=p.size();
    for(int i=0;i<n;++i){
        int t=ccw(p[(i+n-1)%n],p[i],p[(i+1)%n]);
        f&=t!=CCW_CLOCKWISE;
    }
    return f;
}

double area(Polygon s){
    double res=0;
    for(int i=0;i<(int)s.size();++i){
        res+=cross(s[i],s[(i+1)%s.size()])/2.0;
    }
    return res;
}

double area(Circle c1,Circle c2){
    double d=abs(c1.c-c2.c);
    if(c1.r+c2.r<=d+EPS) return 0;
    if(d<=fabs(c1.r-c2.r)){
        double r=min(c1.r,c2.r);
        return PI*r*r;
    }
    double res=0;
    for(int k=0;k<2;++k){
        double rc=(d*d+c1.r*c1.r-c2.r*c2.r)/(2*d*c1.r);
        double th=acosl(rc)*2;
        res+=(th-sinl(th))*c1.r*c1.r/2;
        swap(c1,c2);
    }
    return res;
}

Polygon convexCut(Polygon p,Line l){
    Polygon q;
    for(int i=0;i<(int)p.size();++i){
        Point a=p[i],b=p[(i+1)%p.size()];
        if(ccw(l.p1,l.p2,a)!=-1) q.push_back(a);
        if(ccw(l.p1,l.p2,a)*ccw(l.p1,l.p2,b)<0)
            q.push_back(getCrossPointLL(Line(a,b),l));
    }
    return q;
}

Line bisector(Point p1,Point p2){
    Circle c1=Circle(p1,abs(p1-p2)),c2=Circle(p2,abs(p1-p2));
    Polygon p=getCrossPointCC(c1,c2);
    if(cross(p2-p1,p[0]-p1)>0) swap(p[0],p[1]);
    return Line(p[0],p[1]);
}

Vector translate(Vector v,double theta){
    Vector res;
    res.x=cos(theta)*v.x-sin(theta)*v.y;
    res.y=sin(theta)*v.x+cos(theta)*v.y;
    return res;
}

vector<Line> corner(Line l1,Line l2){
    vector<Line> res;
    if(isParallel(l1,l2)){
        double d=getDistanceLP(l1,l2.p1)/2.0;
        Vector v1=l1.p2-l1.p1;
        v1=v1/v1.abs()*d;
        Point p=l2.p1+translate(v1,90.0*(PI/180.0));
        double d1=getDistanceLP(l1,p);
        double d2=getDistanceLP(l2,p);
        if(fabs(d1-d2)>d){
            p=l2.p1+translate(v1,-90.0*(PI/180.0));
        }
        res.push_back(Line(p,p+v1));
    }else{
        Point p=getCrossPointLL(l1,l2);
        Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
        v1=v1/v1.abs();
        v2=v2/v2.abs();
        res.push_back(Line(p,p+(v1+v2)));
        res.push_back(
                Line(p,p+translate(v1+v2,90.0*(PI/180.0))));
    }
    return res;
}

Polygon tangent(Circle c1,Point p2){
    Circle c2=Circle(p2,sqrt(norm(c1.c-p2)-c1.r*c1.r));
    Polygon p=getCrossPointCC(c1,c2);
    sort(p.begin(),p.end());
    return p;
}

vector<Line> tangent(Circle c1,Circle c2){
    vector<Line> ls;
    if(c1.r<c2.r) swap(c1,c2);
    double g=norm(c1.c-c2.c);
    if(equals(g,0)) return ls;
    Point u=(c2.c-c1.c)/sqrt(g);
    Point v=orth(u);
    for(int s=1;s>=-1;s-=2){
        double h=(c1.r+s*c2.r)/sqrt(g);
        if(equals(1-h*h,0)){
            ls.emplace_back(c1.c+u*c1.r,c1.c+(u+v)*c1.r);
        }else if(1-h*h>0){
            Point uu=u*h,vv=v*sqrt(1-h*h);
            ls.emplace_back(
                    c1.c+(uu+vv)*c1.r,c2.c-(uu+vv)*c2.r*s);
            ls.emplace_back(
                    c1.c+(uu-vv)*c1.r,c2.c-(uu-vv)*c2.r*s);
        }
    }

    return ls;
}

double closest_pair(Polygon &a,int l=0,int r=-1){
    if(r<0){
        r=a.size();
        sort(a.begin(),a.end(),sort_x);
    }
    if(r-l<=1) return abs(a[0]-a[1]);
    int m=(l+r)>>1;
    double x=a[m].x;
    double d=min(closest_pair(a,l,m),closest_pair(a,m,r));
    inplace_merge(a.begin()+l,a.begin()+m,a.begin()+r,sort_y);

    Polygon b;
    for(int i=l;i<r;++i){
        if(fabs(a[i].x-x)>=d) continue;
        for(int j=0;j<(int)b.size();++j){
            double dy=a[i].y-next(b.rbegin(),j)->y;
            if(dy>=d) break;
            d=min(d,abs(a[i]-*next(b.rbegin(),j)));
        }
        b.emplace_back(a[i]);
    }
    return d;
}

vector<vector<int>>
segmentArrangement(vector<Segment> &ss, Polygon &ps){
    int n=ss.size();
    for(int i=0;i<n;++i){
        ps.emplace_back(ss[i].p1);
        ps.emplace_back(ss[i].p2);
        for(int j=i+1;j<n;++j)
            if(intersectSS(ss[i],ss[j]))
                ps.emplace_back(getCrossPointSS(ss[i],ss[j]));
    }
    sort(ps.begin(),ps.end());
    ps.erase(unique(ps.begin(),ps.end()),ps.end());

    vector<vector<int> > G(ps.size());
    for(int i=0;i<n;++i){
        vector<pair<double,int> > ls;
        for(int j=0;j<(int)ps.size();++j)
            if(getDistanceSP(ss[i],ps[j])<EPS)
                ls.emplace_back(make_pair(norm(ss[i].p1-ps[j]),j));

        sort(ls.begin(),ls.end());
        for(int j=0;j+1<(int)ls.size();++j){
            int a=ls[j].second,b=ls[j+1].second;
            G[a].emplace_back(b);
            G[b].emplace_back(a);
        }
    }
    for(auto &v:G){
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
    }
    return G;
}

struct EndPoint{
    Point p;
    int seg,st;
    EndPoint(){}
    EndPoint(Point p,int seg,int st):p(p),seg(seg),st(st){}
    bool operator<(const EndPoint &ep)const{
        if(p.y==ep.p.y) return st<ep.st;
        return p.y<ep.p.y;
    }
};

int manhattan_intersection(
        vector<Segment> ss,const int INF){
    const int BTM = 0;
    const int LFT = 1;
    const int RGH = 2;
    const int TOP = 3;

    int n=ss.size();
    vector<EndPoint> ep;
    for(int i=0;i<n;++i){
        if(ss[i].p1.y==ss[i].p2.y){
            if(ss[i].p1.x>ss[i].p2.x) swap(ss[i].p1,ss[i].p2);
            ep.emplace_back(ss[i].p1,i,LFT);
            ep.emplace_back(ss[i].p2,i,RGH);
        }else{
            if(ss[i].p1.y>ss[i].p2.y) swap(ss[i].p1,ss[i].p2);
            ep.emplace_back(ss[i].p1,i,BTM);
            ep.emplace_back(ss[i].p2,i,TOP);
        }
    }
    sort(ep.begin(),ep.end());

    set<int> bt;
    bt.insert(INF);

    int cnt=0;
    for(int i=0;i<n*2;++i){
        if(ep[i].st==TOP){
            bt.erase(ep[i].p.x);
        }else if(ep[i].st==BTM){
            bt.emplace(ep[i].p.x);
        }else if(ep[i].st==LFT){
            auto b=bt.lower_bound(ss[ep[i].seg].p1.x);
            auto e=bt.upper_bound(ss[ep[i].seg].p2.x);
            cnt+=distance(b,e);
        }
    }

    return cnt;
}

double area(Polygon ps,Circle c){
    if(ps.size()<3u) return 0;
    function<double(Circle, Point, Point)> dfs=
            [&](Circle c,Point a,Point b){
                Vector va=c.c-a,vb=c.c-b;
                double f=cross(va,vb),res=0;
                if(equals(f,0.0)) return res;
                if(max(abs(va),abs(vb))<c.r+EPS) return f;
                Vector d(dot(va,vb),cross(va,vb));
                if(getDistanceSP(Segment(a,b),c.c)>c.r-EPS)
                    return c.r*c.r*atan2(d.y,d.x);
                auto u=getCrossPointCS(c,Segment(a,b));
                if(u.empty()) return res;
                if(u.size()>1u and dot(u[1]-u[0],a-u[0])>0)
                    swap(u[0],u[1]);
                u.emplace(u.begin(),a);
                u.emplace_back(b);
                for(int i=1;i<(int)u.size();++i)
                    res+=dfs(c,u[i-1],u[i]);
                return res;
            };
    double res=0;
    for(int i=0;i<(int)ps.size();++i)
        res+=dfs(c,ps[i],ps[(i+1)%ps.size()]);
    return res/2;
}
//end




using Graph =vector<vector<int>>;

int main(){
    int n,m;
    cin>>n>>m;
    vector<Segment> S;
    for (int i=0; i<n; i++){
        int l;
        cin>>l;
        vector<pii> P(l);
        for (int i=0; i<l; i++){
            cin>>P[i].first>>P[i].second;
        }
        for (int i=0; i<l; i++){
            Point p1(P[i].first,P[i].second);
            Point p2(P[(i+1)%l].first,P[(i+1)%l].second);
            S.push_back(Segment(p1,p2));
        }

    }
    vector<pii>People(m);
    for (int i=0; i<m; i++){
        cin>>People[i].first>>People[i].second;
    }

    int h=500;
    int ans=0;
    for (int x=-h; x<=h; x++ ){
        for (int y=-h; y<=h; y++){
            Point p0(x,y);
            int sans=0;
            for (int i=0; i<m; i++){
                Point pp(People[i].first,People[i].second);
                bool f=true;
                Segment s={p0,pp};
                for (auto t: S){
                    if (intersectSS(s,t)){
                        f=false;
                        break;
                    }
                }
                if (f)sans++;
                
            }
            ans=max(ans,sans);
        }
    }
    cout<<ans<<endl;



}
accuracy: 0.06521739130434782
time_ms: 130
memory_kb: 3412
final_rank: 18

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
#define rep(i,n) for(ll i=0;i<ll(n);i++)
#define all(A) A.begin(),A.end()

// void chmax(ll& p, ll q) { p = max(p, q); };
// void chmin(ll& p, ll q) { p = min(p, q); };

const ll mod = 998244353;


using ll = long long;
const int INF = 1000000000;
const ll LINF = 1001002003004005006ll;
int dx[] = { 1,0,-1,0 }, dy[] = { 0,1,0,-1 };
// ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
template<class T>bool chmax(T& a, const T& b) { if (a < b) { a = b; return true; }return false; }
template<class T>bool chmin(T& a, const T& b) { if (b < a) { a = b; return true; }return false; }
#define ALL(A) A.begin(),A.end()

struct IOSetup {
    IOSetup() {
        cin.tie(0);
        ios::sync_with_stdio(0);
        cout << fixed << setprecision(12);
    }
} iosetup;

template<typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int)v.size(); i++) os << v[i] << (i + 1 == (int)v.size() ? "" : " ");
    return os;
}
template<typename T>
istream& operator>>(istream& is, vector<T>& v) {
    for (T& x : v)is >> x;
    return is;
}

#line 1 "Geometry/template.cpp"
// Real
using Real = double;
const Real EPS = 1e-6;
const Real pi = acosl(-1);

// Point
using Point = complex<Real>;
istream& operator>>(istream& is, Point& p) {
    Real a, b;
    is >> a >> b;
    p = Point(a, b);
    return is;
}
ostream& operator<<(ostream& os, Point& p) {
    return os << fixed << setprecision(12) << p.real() << ' ' << p.imag();
}
inline bool eq(Real a, Real b) {
    return fabs(a - b) < EPS;
}
Point operator*(const Point& p, const Real& d) {
    return Point(real(p) * d, imag(p) * d);
}

// Line
struct Line {
    Point p1, p2;
    Line() = default;
    Line(Point p1, Point p2) :p1(p1), p2(p2) {}
    //Ax + By = C
    Line(Real A, Real B, Real C) {
        if (eq(A, 0))     p1 = Point(0, C / B), p2 = Point(1, C / B);
        else if (eq(B, 0))p1 = Point(C / A, 0), p2 = Point(C / A, 1);
        else            p1 = Point(0, C / B), p2 = Point(C / A, 0);
    }
};

// Segment
struct Segment :Line {
    Segment() = default;
    Segment(Point p1, Point p2) :Line(p1, p2) {}
};
struct Circle {
    Point center;
    Real r;
    Circle() = default;
    Circle(Point center, Real r) :center(center), r(r) {}
};

// Polygon
using Polygon = vector<Point>;
#line 1 "Geometry/Rotate.cpp"
Point rotate(Real theta, Point p) {
    return Point(cos(theta) * real(p) - sin(theta) * imag(p), sin(theta) * real(p) + cos(theta) * imag(p));
}
#line 1 "Geometry/Dot.cpp"
// Dot
Real dot(Point a, Point b) {
    return real(a) * real(b) + imag(a) * imag(b);
}
#line 1 "Geometry/Cross.cpp"
// Cross
Real cross(Point a, Point b) {
    return real(a) * imag(b) - imag(a) * real(b);
}
#line 1 "Geometry/CounterClockWise.cpp"
// ccw (counter clockwise) (Requires: cross, dot)
//https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/all/CGL_1_C
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    if (cross(b, c) > EPS)       return  1;//COUNTER CLOCKWISE
    else if (cross(b, c) < -EPS) return -1;//CLOCKWISE
    else if (dot(b, c) < 0)      return  2;//c--a--b ONLINE BACK
    else if (norm(b) < norm(c)) return -2;//a--b--c ONLINE FRONT
    else                     return  0;//a--c--b ON SEGMENT
}
#line 1 "Geometry/Projection.cpp"
// Projection (Requires: dot)
Point projection(Line l, Point p) {
    // ベクトルl乗に点pからおろした垂線の足
    Real k = dot(l.p1 - l.p2, p - l.p1) / norm(l.p1 - l.p2);
    return l.p1 + (l.p1 - l.p2) * k;
}
Point projection(Segment l, Point p) {
    Real k = dot(l.p1 - l.p2, p - l.p1) / norm(l.p1 - l.p2);
    return l.p1 + (l.p1 - l.p2) * k;
}
#line 1 "Geometry/Intersect.cpp"
// Intersect (Requires : ccw, Dots, Cross, Projection)
bool intersect(Line l, Point p) {
    return abs(ccw(l.p1, l.p2, p)) != 1;
}
//直線の交差判定，外積
bool intersect(Line l1, Line l2) {
    return abs(cross(l1.p2 - l1.p1, l2.p2 - l2.p1)) > EPS || abs(cross(l1.p2 - l1.p1, l2.p2 - l1.p1)) < EPS;
}
//線分に点が乗るかの判定，ccw
bool intersect(Segment s, Point p) {
    return ccw(s.p1, s.p2, p) == 0;
}
//直線と線分の交差判定
bool intersect(Line l, Segment s) {
    return cross(l.p2 - l.p1, s.p1 - l.p1) * cross(l.p2 - l.p1, s.p2 - l.p1) < EPS;
}
//円と直線の交差判定
bool intersect(Circle c, Line l) {
    return abs(c.center - projection(l, c.center)) <= c.r + EPS;
}
//円上かどうか，内部かどうかではない
bool intersect(Circle c, Point p) {
    return abs(abs(p - c.center) - c.r) < EPS;
}
//線分と線分の交差判定
bool intersect(Segment s, Segment t) {
    return ccw(s.p1, s.p2, t.p1) * ccw(s.p1, s.p2, t.p2) <= -EPS && ccw(t.p1, t.p2, s.p1) * ccw(t.p1, t.p2, s.p2) <= -EPS;
}
//線分と円の交差判定，交点の個数を返す
int intersect(Circle c, Segment l) {
    Point h = projection(l, c.center);
    //直線まるっと円の外側
    if (norm(h - c.center) - c.r * c.r > EPS)    return 0;
    Real d1 = abs(c.center - l.p1), d2 = abs(c.center - l.p2);
    //線分が円内
    if (d1 < c.r + EPS && d2 < c.r + EPS) return 0;
    if ((d1<c.r - EPS && d2>c.r + EPS) || (d2<c.r - EPS && d1>c.r + EPS)) return 1;
    //円の外部にまるまるはみ出ていないか
    if (dot(l.p1 - h, l.p2 - h) < 0) return 2;
    return 0;
}
//円と円の位置関係，共通接線の個数を返す
int intersect(Circle c1, Circle c2) {
    if (c1.r < c2.r) swap(c1, c2);
    Real d = abs(c1.center - c2.center);
    //2円が離れている
    if (c1.r + c2.r < d)     return 4;
    //2円が外接する
    if (eq(c1.r + c2.r, d)) return 3;
    //2円が交わる
    if (c1.r - c2.r < d)     return 2;
    //円が内接する
    if (eq(c1.r - c2.r, d)) return 1;
    //内包
    return 0;
}
#line 1 "Geometry/Distance.cpp"
// Distance (Requires: Projection, Intersect)
Real dis(Point a, Point b) {
    return abs(a - b);
}
Real dis(Line l, Point p) {
    return abs(p - projection(l, p));
}
Real dis(Segment s, Point p) {
    Point r = projection(s, p);
    if (intersect(s, r)) return abs(r - p);
    return min(abs(s.p1 - p), abs(s.p2 - p));
}
Real dis(Segment a, Segment b) {
    if (intersect(a, b)) return 0;
    return min({ dis(a,b.p1),dis(a,b.p2),dis(b,a.p1),dis(b,a.p2) });
}
Real dis(Polygon a, Polygon b) {
    Real ret = -10;
    int n = (int)a.size(), m = (int)b.size();
    for (int i = 0; i < n; i++)for (int j = 0; j < m; j++) {
        Real d = dis(Segment(a[i], a[(i + 1) % n]), Segment(b[j], b[(j + 1) % m]));
        if (ret < 0) ret = d;
        else      ret = min(ret, d);
    }
    return ret;
}
Real dis(Polygon poly, Point p) {
    Real ret = -10;
    int n = (int)poly.size();
    for (int i = 0; i < n; i++) {
        Real d = dis(Segment(poly[i], poly[(i + 1) % n]), p);
        if (ret < 0) ret = d;
        else      ret = min(ret, d);
    }
    return ret;
}
#line 1 "Geometry/CrossPoint.cpp"
//intersectをチェックすること
//v
Point crosspoint(Line l, Line m) {
    Real A = cross(m.p2 - m.p1, m.p1 - l.p1);
    Real B = cross(m.p2 - m.p1, l.p2 - l.p1);
    if (eq(A, 0) && eq(B, 0)) return l.p1;
    if (eq(B, 0))             throw "NAI";
    return l.p1 + A / B * (l.p2 - l.p1);
}
Point crosspoint(Segment l, Segment m) {
    return crosspoint(Line(l), Line(m));
}
vector<Point> crosspoint(Circle c, Line l) {
    vector<Point> ret;
    Point h = projection(l, c.center);
    Real d = sqrt(c.r * c.r - norm(h - c.center));
    Point e = (l.p2 - l.p1) * (1 / abs(l.p2 - l.p1));
    if (c.r * c.r + EPS < norm(h - c.center)) return ret;
    if (eq(dis(l, c.center), c.r)) {
        ret.push_back(h);
        return ret;
    }
    ret.push_back(h + e * d); ret.push_back(h - e * d);
    return ret;
}
//要verify，
vector<Point> crosspoint(Circle c, Segment s) {
    Line l = Line(s.p1, s.p2);
    int ko = intersect(c, s);
    if (ko == 2) return crosspoint(c, l);
    vector<Point> ret;
    if (ko == 0) return ret;
    ret = crosspoint(c, l);
    if (ret.size() == 1) return ret;
    vector<Point> rret;
    //交点で挟める方を返す
    if (dot(s.p1 - ret[0], s.p2 - ret[0]) < 0)  rret.push_back(ret[0]);
    else                                rret.push_back(ret[1]);
    return rret;
}
//v
vector<Point> crosspoint(Circle c1, Circle c2) {
    vector<Point> ret;
    int isec = intersect(c1, c2);
    if (isec == 0 || isec == 4) return ret;
    Real d = abs(c1.center - c2.center);
    Real a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
    Real t = atan2(c2.center.imag() - c1.center.imag(), c2.center.real() - c1.center.real());
    ret.push_back(c1.center + Point(cos(t + a) * c1.r, sin(t + a) * c1.r));
    ret.push_back(c1.center + Point(cos(t - a) * c1.r, sin(t - a) * c1.r));
    return ret;
}
#line 1 "Geometry/Angle.cpp"
// angle of a-b-c
Real get_smaller_angle(Point a, Point b, Point c) {
    Point v = a - b, w = c - b;
    auto A = atan2(imag(v), real(v));
    auto B = atan2(imag(w), real(w));
    if (A > B) swap(A, B);
    Real res = B - A;
    return min(res, pi * 2.0 - res);
}
#line 1 "Geometry/InscribedCircle.cpp"
// 内接円
Circle inscribed_circle(Point a, Point b, Point c) {
    Real A, B;
    {
        Point t = c - a;
        t *= conj(b - a);
        t /= norm(b - a);
        A = atan2(imag(t), real(t));
    }
    {
        Point t = a - b;
        t *= conj(c - b);
        t /= norm(c - b);
        B = atan2(imag(t), real(t));
    }
    Line Amid = Line(a, a + rotate(A * 0.5, b - a)), Bmid = Line(b, b + rotate(B * 0.5, c - b));
    auto center = crosspoint(Amid, Bmid);
    auto h = projection(Line(a, b), center);
    return Circle(center, dis(h, center));
}
#line 1 "Geometry/CircumscribedCircle.cpp"
// 外接円
Circle circumscribed_circle(Point a, Point b, Point c) {
    Line orth_ab((a + b) * 0.5, (a + b) * 0.5 + Point(-imag(b - a), real(b - a)));
    Line orth_bc((b + c) * 0.5, (b + c) * 0.5 + Point(-imag(c - b), real(c - b)));
    Point center = crosspoint(orth_ab, orth_bc);
    Real r = dis(a, center);
    return Circle(center, r);
}
#line 1 "Geometry/Tangent.cpp"
//v
//点pから引いた円cの接線の接点を返す
vector<Point> tangent(Circle c, Point p) {
    return crosspoint(c, Circle(p, sqrt(norm(c.center - p) - c.r * c.r)));
}
//v
//二円の共通接線，Lineの2点は接点を表す
vector<Line> tangent(Circle c1, Circle c2) {
    vector<Line> ret;
    if (c1.r < c2.r) swap(c1, c2);
    Real g = norm(c1.center - c2.center);
    if (eq(g, 0)) return ret;
    Point u = (c2.center - c1.center) / sqrt(g);
    Point v = rotate(pi * 0.5, u);
    for (int s : {-1, 1}) {
        Real h = (c1.r + s * c2.r) / sqrt(g);
        if (eq(1 - h * h, 0)) {
            ret.push_back(Line(c1.center + u * c1.r, c1.center + (u + v) * c1.r));
        }
        else if (1 - h * h > 0) {
            Point uu = u * h, vv = v * sqrt(1 - h * h);
            ret.push_back(Line(c1.center + (uu + vv) * c1.r, c2.center - (uu + vv) * c2.r * s));
            ret.push_back(Line(c1.center + (uu - vv) * c1.r, c2.center - (uu - vv) * c2.r * s));
        }
    }
    return ret;
}
#line 1 "Geometry/Contain.cpp"
// out 0, on 1, in 2
int contains(Polygon poly, Point p) {
    int res = 0;
    int n = (int)poly.size();
    for (int i = 0; i < n; i++) {
        Point a = poly[i] - p, b = poly[(i + 1) % n] - p;
        if (imag(a) > imag(b)) swap(a, b);
        if (imag(a) <= 0 && 0 < imag(b) && cross(a, b) < 0) res ^= 1;
        if (eq(cross(a, b), 0) && (dot(a, b) < 0 || eq(dot(a, b), 0))) return 1;
    }
    if (res) res = 2;
    return res;
}
#line 1 "Geometry/MinimumBoundingCircle.cpp"
//最小包含円を返す　計算量は期待値O(n)
/*
Circle MinimumBoundingCircle(vector<Point> v){
    int n=v.size();
    //ランダムシャッフル．いぢわるされたくないもんだ
    mt19937 mt(time(0));
    shuffle(v.begin(),v.end(),mt);
    Circle ret(0,0);

    auto make_circle2=[&](Point a,Point b){
        return Circle((a+b)*0.5,dis(a,b)/2);
    };

    auto make_circle3=[&](Point A,Point B,Point C){
        Point cent=circumscribed_circle(A,B,C).center;
        return Circle(cent,dis(cent,A));
    };

    auto isIn=[&](Point a){
        return dis(ret.center,a)<ret.r+EPS;
    };

    ret=make_circle2(v[0],v[1]);
    for(int i=2;i<n;i++){
        //v[i]が円に入っていないなら
        if(!isIn(v[i])){
            //円内にないなら点v[i]は必ず円周上に来る
            ret=make_circle2(v[0],v[i]);
            for(int j=1;j<i;j++){
                if(!isIn(v[j])){
                    //この時iとjが円周上を考える
                    ret=make_circle2(v[i],v[j]);
                    //最後の1点の決定
                    for(int k=0;k<j;k++)if(!isIn(v[k])) ret=make_circle3(v[i],v[j],v[k]);
                }
            }
        }
    }
    return ret;
}*/
#line 1 "Geometry/ClosestPair.cpp"
// 最近点対
// O(NlogN)
Real closest_pair(vector<Point> ps) {
    sort(ALL(ps), [&](Point a, Point b) {
        return real(a) < real(b);
        });
    function<Real(int, int)> rec = [&](int l, int r) {
        if (r - l <= 1) return (Real)1e18;
        int m = (l + r) / 2;
        Real x = real(ps[m]);
        Real ret = min(rec(l, m), rec(m, r));
        inplace_merge(begin(ps) + l, begin(ps) + m, begin(ps) + r, [&](Point a, Point b) {
            return imag(a) < imag(b);
            });
        // 分割を跨いで最小距離があるか調べる
        vector<Point> b;
        for (int i = l; i < r; i++) {
            if (abs(real(ps[i]) - x) >= ret) continue;
            for (int j = (int)b.size() - 1; j >= 0; j--) {
                if (abs(imag(ps[i] - b[j])) >= ret) break;
                ret = min(ret, abs(ps[i] - b[j]));
            }
            b.push_back(ps[i]);
        }
        return ret;
    };
    return rec(0, (int)ps.size());
}
#line 1 "Geometry/Convex.cpp"
// 凸多角形系統
// 凸多角形の頂点は反時計周りに訪れる順序
// v
// 頂点は反時計周りに訪れる順序，時計回りとなるような3点があるとfalse
bool is_convex(const vector<Point>& ps) {
    int n = (int)ps.size();
    for (int i = 0; i < n; i++)if (ccw(ps[(i + n - 1) % n], ps[i], ps[(i + 1) % n]) == -1)return false;
    return true;
}

// 凸包，あんまりよくわかってない．直線状に頂点をのせない場合(↑)，のせる場合(↓)
vector<Point> convex_hull(vector<Point> p) {
    int n = (int)p.size(), k = 0;
    if (n <= 2)return p;
    sort(begin(p), end(p), [](Point a, Point b) {
        return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
        });
    vector<Point>ch(2 * n);
    for (int i = 0; i < n; ch[k++] = p[i++]) {
        // while(k>=2 and cross(ch[k-1]-ch[k-2],p[i]-ch[k-1])<EPS)k--;
        while (k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0)k--;
    }
    for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
        // while(k>=t and cross(ch[k-1]-ch[k-2],p[i]-ch[k-1])<EPS)k--;
        while (k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0)k--;
    }
    ch.resize(k - 1);
    return ch;
}

vector<Point> crosspoint(Polygon poly, Circle c) {
    int n = (int)poly.size();
    vector<Point> ret;
    rep(i, n) {
        Segment seg = Segment(poly[i], poly[(i + 1) % n]);
        auto ps = crosspoint(c, seg);
        for (auto& p : ps) ret.push_back(p);
    }
    return ret;
}




#line 18 "Geometry/include.cpp"

Real get(Point a, Point b, Point c) {
    a -= b;
    c -= b;
    Real ret = atan2(real(c), imag(c)) - atan2(real(a), imag(a));
    while (ret > pi * 2) ret -= pi * 2;
    while (ret < 0) ret += pi * 2;
    return ret;
}

/*
aを中心とし，bをradだけ回すような扇と
polyの交差判定

polyとa-bの交差判定は行わない
*/
bool cross(Polygon& poly, Point a, Point b, Real rad) {
    int n = (int)poly.size();
    Real l = dis(a, b);
    Point v = rotate(rad, b - a) / l;
    // 多角形の返上に棒が載っている時，常にaで交差判定がtrueになるんじゃないか？
    // EPSだけズラしてみた．わからない
    Segment abrot = Segment(a + v * EPS, a + v * l);
    rep(i, n) {
        Segment seg = Segment(poly[i], poly[(i + 1) % n]);

        if (intersect(seg, abrot)) return true;
        auto h = projection(seg, a);
        auto hr = get(b, a, h);
        if (hr <= rad) return true;
    }
    return false;
}


int main() {

    cin.tie(nullptr);
    ios::sync_with_stdio(false);

    ll N,M;
    cin>>N>>M;

    vector<Polygon> P(N);
    rep(i,N){
        ll L;
        cin>>L;
        vector<Point> U(L);
        rep(_,L){
            double x,y;
            cin>>x>>y;
            U[_]={x,y};
        }
        P[i]=U;
    }
    vector<Point> H(M);
    rep(_,M){
        double x,y;
        cin>>x>>y;
        H[_]={x,y};
    }
    ll an=0;
    vector<Line> S;
    rep(i,M)rep(j,N){
        for(auto u:P[j]){
            S.push_back(Line(H[i],u));
        }
    }
    ll SN=S.size();
    rep(i,SN)rep(j,SN){
        if(intersect(S[i],S[j])){
            Point CCP=crosspoint(S[i],S[j]);

            
            rep(j,11){
                ll res=M;
                Point CP=CCP;
                if(j!=10){
                    Point ER={0.1*cos(pi*double(j)/5.0),0.1*sin(pi*double(j)/5.0)};
                    CP+=ER;
                }
                rep(m,M){
                    bool OK=1;
                    rep(n,N){
                        
                        rep(k,P[n].size()){
                            if(intersect(Segment(H[m],CP),Segment(P[n][k],P[n][(k+1)%ll(P[n].size())])))OK=0;
                        }
                        
                    }
                    if(!OK)res--;
                }
                chmax(an,res);
            }
           
        }
    }

    cout<<an<<endl;
}
accuracy: 1
time_ms: 570
memory_kb: 3844
final_rank: 12

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
#define rep(i,n) for(ll i=0;i<ll(n);i++)
#define all(A) A.begin(),A.end()

// void chmax(ll& p, ll q) { p = max(p, q); };
// void chmin(ll& p, ll q) { p = min(p, q); };

const ll mod = 998244353;


using ll = long long;
const int INF = 1000000000;
const ll LINF = 1001002003004005006ll;
int dx[] = { 1,0,-1,0 }, dy[] = { 0,1,0,-1 };
// ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
template<class T>bool chmax(T& a, const T& b) { if (a < b) { a = b; return true; }return false; }
template<class T>bool chmin(T& a, const T& b) { if (b < a) { a = b; return true; }return false; }
#define ALL(A) A.begin(),A.end()

struct IOSetup {
    IOSetup() {
        cin.tie(0);
        ios::sync_with_stdio(0);
        cout << fixed << setprecision(12);
    }
} iosetup;

template<typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int)v.size(); i++) os << v[i] << (i + 1 == (int)v.size() ? "" : " ");
    return os;
}
template<typename T>
istream& operator>>(istream& is, vector<T>& v) {
    for (T& x : v)is >> x;
    return is;
}

#line 1 "Geometry/template.cpp"
// Real
using Real = double;
const Real EPS = 1e-6;
const Real pi = acosl(-1);

// Point
using Point = complex<Real>;
istream& operator>>(istream& is, Point& p) {
    Real a, b;
    is >> a >> b;
    p = Point(a, b);
    return is;
}
ostream& operator<<(ostream& os, Point& p) {
    return os << fixed << setprecision(12) << p.real() << ' ' << p.imag();
}
inline bool eq(Real a, Real b) {
    return fabs(a - b) < EPS;
}
Point operator*(const Point& p, const Real& d) {
    return Point(real(p) * d, imag(p) * d);
}

// Line
struct Line {
    Point p1, p2;
    Line() = default;
    Line(Point p1, Point p2) :p1(p1), p2(p2) {}
    //Ax + By = C
    Line(Real A, Real B, Real C) {
        if (eq(A, 0))     p1 = Point(0, C / B), p2 = Point(1, C / B);
        else if (eq(B, 0))p1 = Point(C / A, 0), p2 = Point(C / A, 1);
        else            p1 = Point(0, C / B), p2 = Point(C / A, 0);
    }
};

// Segment
struct Segment :Line {
    Segment() = default;
    Segment(Point p1, Point p2) :Line(p1, p2) {}
};
struct Circle {
    Point center;
    Real r;
    Circle() = default;
    Circle(Point center, Real r) :center(center), r(r) {}
};

// Polygon
using Polygon = vector<Point>;
#line 1 "Geometry/Rotate.cpp"
Point rotate(Real theta, Point p) {
    return Point(cos(theta) * real(p) - sin(theta) * imag(p), sin(theta) * real(p) + cos(theta) * imag(p));
}
#line 1 "Geometry/Dot.cpp"
// Dot
Real dot(Point a, Point b) {
    return real(a) * real(b) + imag(a) * imag(b);
}
#line 1 "Geometry/Cross.cpp"
// Cross
Real cross(Point a, Point b) {
    return real(a) * imag(b) - imag(a) * real(b);
}
#line 1 "Geometry/CounterClockWise.cpp"
// ccw (counter clockwise) (Requires: cross, dot)
//https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/all/CGL_1_C
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    if (cross(b, c) > EPS)       return  1;//COUNTER CLOCKWISE
    else if (cross(b, c) < -EPS) return -1;//CLOCKWISE
    else if (dot(b, c) < 0)      return  2;//c--a--b ONLINE BACK
    else if (norm(b) < norm(c)) return -2;//a--b--c ONLINE FRONT
    else                     return  0;//a--c--b ON SEGMENT
}
#line 1 "Geometry/Projection.cpp"
// Projection (Requires: dot)
Point projection(Line l, Point p) {
    // ベクトルl乗に点pからおろした垂線の足
    Real k = dot(l.p1 - l.p2, p - l.p1) / norm(l.p1 - l.p2);
    return l.p1 + (l.p1 - l.p2) * k;
}
Point projection(Segment l, Point p) {
    Real k = dot(l.p1 - l.p2, p - l.p1) / norm(l.p1 - l.p2);
    return l.p1 + (l.p1 - l.p2) * k;
}
#line 1 "Geometry/Intersect.cpp"
// Intersect (Requires : ccw, Dots, Cross, Projection)
bool intersect(Line l, Point p) {
    return abs(ccw(l.p1, l.p2, p)) != 1;
}
//直線の交差判定，外積
bool intersect(Line l1, Line l2) {
    return abs(cross(l1.p2 - l1.p1, l2.p2 - l2.p1)) > EPS || abs(cross(l1.p2 - l1.p1, l2.p2 - l1.p1)) < EPS;
}
//線分に点が乗るかの判定，ccw
bool intersect(Segment s, Point p) {
    return ccw(s.p1, s.p2, p) == 0;
}
//直線と線分の交差判定
bool intersect(Line l, Segment s) {
    return cross(l.p2 - l.p1, s.p1 - l.p1) * cross(l.p2 - l.p1, s.p2 - l.p1) < EPS;
}
//円と直線の交差判定
bool intersect(Circle c, Line l) {
    return abs(c.center - projection(l, c.center)) <= c.r + EPS;
}
//円上かどうか，内部かどうかではない
bool intersect(Circle c, Point p) {
    return abs(abs(p - c.center) - c.r) < EPS;
}
//線分と線分の交差判定
bool intersect(Segment s, Segment t) {
    return ccw(s.p1, s.p2, t.p1) * ccw(s.p1, s.p2, t.p2) <= -EPS && ccw(t.p1, t.p2, s.p1) * ccw(t.p1, t.p2, s.p2) <= -EPS;
}
//線分と円の交差判定，交点の個数を返す
int intersect(Circle c, Segment l) {
    Point h = projection(l, c.center);
    //直線まるっと円の外側
    if (norm(h - c.center) - c.r * c.r > EPS)    return 0;
    Real d1 = abs(c.center - l.p1), d2 = abs(c.center - l.p2);
    //線分が円内
    if (d1 < c.r + EPS && d2 < c.r + EPS) return 0;
    if ((d1<c.r - EPS && d2>c.r + EPS) || (d2<c.r - EPS && d1>c.r + EPS)) return 1;
    //円の外部にまるまるはみ出ていないか
    if (dot(l.p1 - h, l.p2 - h) < 0) return 2;
    return 0;
}
//円と円の位置関係，共通接線の個数を返す
int intersect(Circle c1, Circle c2) {
    if (c1.r < c2.r) swap(c1, c2);
    Real d = abs(c1.center - c2.center);
    //2円が離れている
    if (c1.r + c2.r < d)     return 4;
    //2円が外接する
    if (eq(c1.r + c2.r, d)) return 3;
    //2円が交わる
    if (c1.r - c2.r < d)     return 2;
    //円が内接する
    if (eq(c1.r - c2.r, d)) return 1;
    //内包
    return 0;
}
#line 1 "Geometry/Distance.cpp"
// Distance (Requires: Projection, Intersect)
Real dis(Point a, Point b) {
    return abs(a - b);
}
Real dis(Line l, Point p) {
    return abs(p - projection(l, p));
}
Real dis(Segment s, Point p) {
    Point r = projection(s, p);
    if (intersect(s, r)) return abs(r - p);
    return min(abs(s.p1 - p), abs(s.p2 - p));
}
Real dis(Segment a, Segment b) {
    if (intersect(a, b)) return 0;
    return min({ dis(a,b.p1),dis(a,b.p2),dis(b,a.p1),dis(b,a.p2) });
}
Real dis(Polygon a, Polygon b) {
    Real ret = -10;
    int n = (int)a.size(), m = (int)b.size();
    for (int i = 0; i < n; i++)for (int j = 0; j < m; j++) {
        Real d = dis(Segment(a[i], a[(i + 1) % n]), Segment(b[j], b[(j + 1) % m]));
        if (ret < 0) ret = d;
        else      ret = min(ret, d);
    }
    return ret;
}
Real dis(Polygon poly, Point p) {
    Real ret = -10;
    int n = (int)poly.size();
    for (int i = 0; i < n; i++) {
        Real d = dis(Segment(poly[i], poly[(i + 1) % n]), p);
        if (ret < 0) ret = d;
        else      ret = min(ret, d);
    }
    return ret;
}
#line 1 "Geometry/CrossPoint.cpp"
//intersectをチェックすること
//v
Point crosspoint(Line l, Line m) {
    Real A = cross(m.p2 - m.p1, m.p1 - l.p1);
    Real B = cross(m.p2 - m.p1, l.p2 - l.p1);
    if (eq(A, 0) && eq(B, 0)) return l.p1;
    if (eq(B, 0))             throw "NAI";
    return l.p1 + A / B * (l.p2 - l.p1);
}
Point crosspoint(Segment l, Segment m) {
    return crosspoint(Line(l), Line(m));
}
vector<Point> crosspoint(Circle c, Line l) {
    vector<Point> ret;
    Point h = projection(l, c.center);
    Real d = sqrt(c.r * c.r - norm(h - c.center));
    Point e = (l.p2 - l.p1) * (1 / abs(l.p2 - l.p1));
    if (c.r * c.r + EPS < norm(h - c.center)) return ret;
    if (eq(dis(l, c.center), c.r)) {
        ret.push_back(h);
        return ret;
    }
    ret.push_back(h + e * d); ret.push_back(h - e * d);
    return ret;
}
//要verify，
vector<Point> crosspoint(Circle c, Segment s) {
    Line l = Line(s.p1, s.p2);
    int ko = intersect(c, s);
    if (ko == 2) return crosspoint(c, l);
    vector<Point> ret;
    if (ko == 0) return ret;
    ret = crosspoint(c, l);
    if (ret.size() == 1) return ret;
    vector<Point> rret;
    //交点で挟める方を返す
    if (dot(s.p1 - ret[0], s.p2 - ret[0]) < 0)  rret.push_back(ret[0]);
    else                                rret.push_back(ret[1]);
    return rret;
}
//v
vector<Point> crosspoint(Circle c1, Circle c2) {
    vector<Point> ret;
    int isec = intersect(c1, c2);
    if (isec == 0 || isec == 4) return ret;
    Real d = abs(c1.center - c2.center);
    Real a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
    Real t = atan2(c2.center.imag() - c1.center.imag(), c2.center.real() - c1.center.real());
    ret.push_back(c1.center + Point(cos(t + a) * c1.r, sin(t + a) * c1.r));
    ret.push_back(c1.center + Point(cos(t - a) * c1.r, sin(t - a) * c1.r));
    return ret;
}
#line 1 "Geometry/Angle.cpp"
// angle of a-b-c
Real get_smaller_angle(Point a, Point b, Point c) {
    Point v = a - b, w = c - b;
    auto A = atan2(imag(v), real(v));
    auto B = atan2(imag(w), real(w));
    if (A > B) swap(A, B);
    Real res = B - A;
    return min(res, pi * 2.0 - res);
}
#line 1 "Geometry/InscribedCircle.cpp"
// 内接円
Circle inscribed_circle(Point a, Point b, Point c) {
    Real A, B;
    {
        Point t = c - a;
        t *= conj(b - a);
        t /= norm(b - a);
        A = atan2(imag(t), real(t));
    }
    {
        Point t = a - b;
        t *= conj(c - b);
        t /= norm(c - b);
        B = atan2(imag(t), real(t));
    }
    Line Amid = Line(a, a + rotate(A * 0.5, b - a)), Bmid = Line(b, b + rotate(B * 0.5, c - b));
    auto center = crosspoint(Amid, Bmid);
    auto h = projection(Line(a, b), center);
    return Circle(center, dis(h, center));
}
#line 1 "Geometry/CircumscribedCircle.cpp"
// 外接円
Circle circumscribed_circle(Point a, Point b, Point c) {
    Line orth_ab((a + b) * 0.5, (a + b) * 0.5 + Point(-imag(b - a), real(b - a)));
    Line orth_bc((b + c) * 0.5, (b + c) * 0.5 + Point(-imag(c - b), real(c - b)));
    Point center = crosspoint(orth_ab, orth_bc);
    Real r = dis(a, center);
    return Circle(center, r);
}
#line 1 "Geometry/Tangent.cpp"
//v
//点pから引いた円cの接線の接点を返す
vector<Point> tangent(Circle c, Point p) {
    return crosspoint(c, Circle(p, sqrt(norm(c.center - p) - c.r * c.r)));
}
//v
//二円の共通接線，Lineの2点は接点を表す
vector<Line> tangent(Circle c1, Circle c2) {
    vector<Line> ret;
    if (c1.r < c2.r) swap(c1, c2);
    Real g = norm(c1.center - c2.center);
    if (eq(g, 0)) return ret;
    Point u = (c2.center - c1.center) / sqrt(g);
    Point v = rotate(pi * 0.5, u);
    for (int s : {-1, 1}) {
        Real h = (c1.r + s * c2.r) / sqrt(g);
        if (eq(1 - h * h, 0)) {
            ret.push_back(Line(c1.center + u * c1.r, c1.center + (u + v) * c1.r));
        }
        else if (1 - h * h > 0) {
            Point uu = u * h, vv = v * sqrt(1 - h * h);
            ret.push_back(Line(c1.center + (uu + vv) * c1.r, c2.center - (uu + vv) * c2.r * s));
            ret.push_back(Line(c1.center + (uu - vv) * c1.r, c2.center - (uu - vv) * c2.r * s));
        }
    }
    return ret;
}
#line 1 "Geometry/Contain.cpp"
// out 0, on 1, in 2
int contains(Polygon poly, Point p) {
    int res = 0;
    int n = (int)poly.size();
    for (int i = 0; i < n; i++) {
        Point a = poly[i] - p, b = poly[(i + 1) % n] - p;
        if (imag(a) > imag(b)) swap(a, b);
        if (imag(a) <= 0 && 0 < imag(b) && cross(a, b) < 0) res ^= 1;
        if (eq(cross(a, b), 0) && (dot(a, b) < 0 || eq(dot(a, b), 0))) return 1;
    }
    if (res) res = 2;
    return res;
}
#line 1 "Geometry/MinimumBoundingCircle.cpp"
//最小包含円を返す　計算量は期待値O(n)
/*
Circle MinimumBoundingCircle(vector<Point> v){
    int n=v.size();
    //ランダムシャッフル．いぢわるされたくないもんだ
    mt19937 mt(time(0));
    shuffle(v.begin(),v.end(),mt);
    Circle ret(0,0);

    auto make_circle2=[&](Point a,Point b){
        return Circle((a+b)*0.5,dis(a,b)/2);
    };

    auto make_circle3=[&](Point A,Point B,Point C){
        Point cent=circumscribed_circle(A,B,C).center;
        return Circle(cent,dis(cent,A));
    };

    auto isIn=[&](Point a){
        return dis(ret.center,a)<ret.r+EPS;
    };

    ret=make_circle2(v[0],v[1]);
    for(int i=2;i<n;i++){
        //v[i]が円に入っていないなら
        if(!isIn(v[i])){
            //円内にないなら点v[i]は必ず円周上に来る
            ret=make_circle2(v[0],v[i]);
            for(int j=1;j<i;j++){
                if(!isIn(v[j])){
                    //この時iとjが円周上を考える
                    ret=make_circle2(v[i],v[j]);
                    //最後の1点の決定
                    for(int k=0;k<j;k++)if(!isIn(v[k])) ret=make_circle3(v[i],v[j],v[k]);
                }
            }
        }
    }
    return ret;
}*/
#line 1 "Geometry/ClosestPair.cpp"
// 最近点対
// O(NlogN)
Real closest_pair(vector<Point> ps) {
    sort(ALL(ps), [&](Point a, Point b) {
        return real(a) < real(b);
        });
    function<Real(int, int)> rec = [&](int l, int r) {
        if (r - l <= 1) return (Real)1e18;
        int m = (l + r) / 2;
        Real x = real(ps[m]);
        Real ret = min(rec(l, m), rec(m, r));
        inplace_merge(begin(ps) + l, begin(ps) + m, begin(ps) + r, [&](Point a, Point b) {
            return imag(a) < imag(b);
            });
        // 分割を跨いで最小距離があるか調べる
        vector<Point> b;
        for (int i = l; i < r; i++) {
            if (abs(real(ps[i]) - x) >= ret) continue;
            for (int j = (int)b.size() - 1; j >= 0; j--) {
                if (abs(imag(ps[i] - b[j])) >= ret) break;
                ret = min(ret, abs(ps[i] - b[j]));
            }
            b.push_back(ps[i]);
        }
        return ret;
    };
    return rec(0, (int)ps.size());
}
#line 1 "Geometry/Convex.cpp"
// 凸多角形系統
// 凸多角形の頂点は反時計周りに訪れる順序
// v
// 頂点は反時計周りに訪れる順序，時計回りとなるような3点があるとfalse
bool is_convex(const vector<Point>& ps) {
    int n = (int)ps.size();
    for (int i = 0; i < n; i++)if (ccw(ps[(i + n - 1) % n], ps[i], ps[(i + 1) % n]) == -1)return false;
    return true;
}

// 凸包，あんまりよくわかってない．直線状に頂点をのせない場合(↑)，のせる場合(↓)
vector<Point> convex_hull(vector<Point> p) {
    int n = (int)p.size(), k = 0;
    if (n <= 2)return p;
    sort(begin(p), end(p), [](Point a, Point b) {
        return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
        });
    vector<Point>ch(2 * n);
    for (int i = 0; i < n; ch[k++] = p[i++]) {
        // while(k>=2 and cross(ch[k-1]-ch[k-2],p[i]-ch[k-1])<EPS)k--;
        while (k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0)k--;
    }
    for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
        // while(k>=t and cross(ch[k-1]-ch[k-2],p[i]-ch[k-1])<EPS)k--;
        while (k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0)k--;
    }
    ch.resize(k - 1);
    return ch;
}

vector<Point> crosspoint(Polygon poly, Circle c) {
    int n = (int)poly.size();
    vector<Point> ret;
    rep(i, n) {
        Segment seg = Segment(poly[i], poly[(i + 1) % n]);
        auto ps = crosspoint(c, seg);
        for (auto& p : ps) ret.push_back(p);
    }
    return ret;
}




#line 18 "Geometry/include.cpp"

Real get(Point a, Point b, Point c) {
    a -= b;
    c -= b;
    Real ret = atan2(real(c), imag(c)) - atan2(real(a), imag(a));
    while (ret > pi * 2) ret -= pi * 2;
    while (ret < 0) ret += pi * 2;
    return ret;
}

/*
aを中心とし，bをradだけ回すような扇と
polyの交差判定

polyとa-bの交差判定は行わない
*/
bool cross(Polygon& poly, Point a, Point b, Real rad) {
    int n = (int)poly.size();
    Real l = dis(a, b);
    Point v = rotate(rad, b - a) / l;
    // 多角形の返上に棒が載っている時，常にaで交差判定がtrueになるんじゃないか？
    // EPSだけズラしてみた．わからない
    Segment abrot = Segment(a + v * EPS, a + v * l);
    rep(i, n) {
        Segment seg = Segment(poly[i], poly[(i + 1) % n]);

        if (intersect(seg, abrot)) return true;
        auto h = projection(seg, a);
        auto hr = get(b, a, h);
        if (hr <= rad) return true;
    }
    return false;
}


int main() {

    cin.tie(nullptr);
    ios::sync_with_stdio(false);

    ll N,M;
    cin>>N>>M;

    vector<Polygon> P(N);
    rep(i,N){
        ll L;
        cin>>L;
        vector<Point> U(L);
        rep(_,L){
            double x,y;
            cin>>x>>y;
            U[_]={x,y};
        }
        P[i]=U;
    }
    vector<Point> H(M);
    rep(_,M){
        double x,y;
        cin>>x>>y;
        H[_]={x,y};
    }
    ll an=0;
    vector<Line> S;
    rep(i,M)rep(j,N){
        for(auto u:P[j]){
            S.push_back(Line(H[i],u));
        }
    }
    ll SN=S.size();
    rep(i,SN)rep(j,SN){
        if(intersect(S[i],S[j])){
            Point CCP=crosspoint(S[i],S[j]);

            
            rep(j,11){
                ll res=M;
                Point CP=CCP;
                if(j!=10){
                    Point ER={0.1*cos(pi*double(j)/5.0),0.1*sin(pi*double(j)/5.0)};
                    CP+=ER;
                }
                rep(m,M){
                    rep(n,N){
                        bool OK=1;
                        rep(k,P[n].size()){
                            if(intersect(Segment(H[m],CP),Segment(P[n][k],P[n][(k+1)%ll(P[n].size())])))OK=0;
                        }
                        if(!OK)res--;
                    }
                }
                chmax(an,res);
            }
           
        }
    }

    cout<<an<<endl;
}
accuracy: 0.43478260869565216
time_ms: 560
memory_kb: 3836
final_rank: 16

code_snippet: #include <bits/stdc++.h>

using Point = std::pair<long double, long double>;
using Segment = std::pair<Point, Point>;
using Line = std::pair<Point, Point>;
using Polygon = std::vector<Point>;

constexpr long double EPS{(long double)1e-12};

Point operator+(const Point& l, const Point& r) {
    return Point{ l.first + r.first, l.second + r.second };
}

Point operator-(const Point& l, const Point& r) {
    return Point{ l.first - r.first, l.second - r.second };
}

Point operator*(const Point& p, long double k) {
    return Point{ p.first * k, p.second * k };
}

long double Cross(const Point& l, const Point& r) {
    return l.first * r.second - l.second * r.first;
}

long double Dot(const Point& l, const Point& r) {
    return l.first * r.first + l.second * r.second;
}

bool Zero(long double v) {
    return std::abs(v) < EPS;
}

bool Intersetct(const Line& l, const Line& r) {
    if (!Zero(Cross(l.second - l.first, r.second - r.first))) {
        return true;
    }
    else if (!Zero(Cross(l.second - l.first, r.first - l.first))) {
        return false;
    }
    else {
        return true;
    }
}

Point CrossPoint(const Line& l, const Line& r) {
    assert(Intersetct(l, r));
    return l.first + (l.second - l.first) * (Cross(r.first - l.first, l.second - l.first) / Cross(l.second - l.first, r.second - r.first));
}

enum RELATION {
    ONLINE_FRONT = -2,
    CLOCKWISE,
    ON_SEGMENT,
    COUNTER_CLOCKWISE,
    ONLINE_BACK
};

RELATION Relation(const Point& p0, const Point& p1, const Point& p2) {
    Point a{p1 - p0}, b{p2 - p0};
    if (Cross(a, b) > EPS) return COUNTER_CLOCKWISE;
    if (Cross(a, b) < -EPS) return CLOCKWISE;
    if (Dot(a, b) < -EPS) return ONLINE_BACK;
    if (Dot(b, b) - Dot(a, a) > EPS) ONLINE_FRONT;
    return ON_SEGMENT;
}

bool Straddle(const Segment& l, const Segment& r) {
    return Relation(l.first, l.second, r.first) * Relation(l.first, l.second, r.second) <= 0;
}

bool IntersectSegment(const Segment& l, const Segment& r) {
    return Straddle(l, r) and Straddle(r, l);
}

std::ostream& operator<<(std::ostream& os, const Point& p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}

bool Intersect(const Polygon& P, const Segment& s) {
    bool res{};
    for (int i{} ; i < (int)P.size() ; i++) {
        Segment t{P[i], P[i + 1 == (int)P.size() ? 0 : i + 1]};
        // std::cout << "seg is " << t.first << ' ' << t.second << std::endl;
        if (Relation(s.first, t.first, s.second) == ON_SEGMENT) continue;
        if (Relation(s.first, t.second, s.second) == ON_SEGMENT) continue;
        if (Relation(t.first, s.first, t.second) == ON_SEGMENT) continue;
        if (Relation(t.first, s.second, t.second) == ON_SEGMENT) continue;
        // std::cout << "not haji" << std::endl;
        if (IntersectSegment(s, t)) {
            res = true;
            // std::cout << "intersect!" << std::endl;
        }
    }
    return res;
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    int N, M;
    std::cin >> N >> M;
    std::vector<Polygon> P(N);
    for (int i{} ; i < N ; i++) {
        int L;
        std::cin >> L;
        for (int j{} ; j < L ; j++) {
            long double x, y;
            std::cin >> x >> y;
            P[i].emplace_back(x, y);
        }
    }
    std::vector<Point> Q(M);
    for (auto& [x, y] : Q) {
        std::cin >> x >> y;
    }
    std::vector<Point> cond;
    for (int i{} ; i < M ; i++) {
        for (int j{i + 1} ; j < M ; j++) {
            for (const auto& poly1 : P) {
                for (const auto& poly2 : P) {
                    for (const auto& p1 : poly1) {
                        for (const auto& p2 : poly2) {
                            Line l1{Q[i], p1};
                            Line l2{Q[j], p2};
                            if (!Intersetct(l1, l2)) continue;
                            cond.push_back(CrossPoint(l1, l2));
                        }
                    }
                }
            }
        }
    }
    // cond.clear();
    // cond.emplace_back(0.0, 3.0);
    int ans{1};
    for (const auto& c : cond) {
        // if (-1.1 <= c.first and c.first <= 1.1 and 1.9 <= c.second and c.second <= 3.1) {
        //     std::cout << c.first << ',' << c.second << std::endl;
        // }
        int val{};
        for (const auto& q : Q) {
            Segment seg{c, q};
            // std::cout << "I have " << seg.first << ' ' << seg.second << std::endl;
            bool ok{true};
            for (const auto& p : P) {
                // std::cout << "check" << std::endl;
                ok &= !Intersect(p, seg);
            }
            if (ok) val++;
        }
        // if (val == 2) {
        //     std::cout << c.first << ',' << c.second << std::endl;
        // }
        ans = std::max(ans, val);
    }
    std::cout << ans << '\n';
}
accuracy: 1
time_ms: 40
memory_kb: 3836
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using P = pair<ll, ll>;
#define rep(i, a, b) for(ll i = a; i < b; ++i)
#define rrep(i, a, b) for(ll i = a; i >= b; --i)
constexpr ll inf = 4e18;
using Real = long double;
const Real EPS = 1e-6, PI = acos(Real(-1.0));
int sign(const Real& r) {
    if(r <= -EPS) return -1;
    if(r >= +EPS) return +1;
    return 0;
}
bool eq(const Real& a, const Real& b) {
    return sign(a - b) == 0;
}
using Point = complex<Real>;
istream& operator>>(istream& is, Point& p) {
    Real a, b;
    is >> a >> b;
    p = Point(a, b);
    return is;
}
ostream& operator<<(ostream& os, const Point& p) {
    return os << p.real() << ' ' << p.imag();
}
Real dot(const Point& p1, const Point& p2) {
    return (conj(p1) * p2).real();
}
Real cross(const Point& p1, const Point& p2) {
    return (conj(p1) * p2).imag();
}
int ccw(const Point& a, Point b, Point c) {
    b -= a;
    c -= a;
    if(sign(cross(b, c)) == 1) return 1;
    if(sign(cross(b, c)) == -1) return -1;
    if(sign(dot(b, c)) == -1) return +2;
    if(norm(b) < norm(c)) return -2;
    return 0;
}
struct Line {
    Point a, b;
    Line() = default;
    Line(const Point& a, const Point& b)
        : a(a), b(b) {}
};
using Segment = Line;
bool is_intersect_ll(const Line& l1, const Line& l2) {
    if(!eq(cross(l1.b - l1.a, l2.b - l2.a), 0.0)) return true;
    return eq(cross(l1.b - l1.a, l2.b - l1.a), 0.0);
}
bool is_intersect_ss(const Segment& s1, const Segment& s2) {
    if(ccw(s1.a, s1.b, s2.a) * ccw(s1.a, s1.b, s2.b) > 0) return false;
    return ccw(s2.a, s2.b, s1.a) * ccw(s2.a, s2.b, s1.b) <= 0;
}
vector<Point> intersection_ll(const Line& l1, const Line& l2) {
    vector<Point> res;
    if(!is_intersect_ll(l1, l2)) return res;
    Real a = cross(l1.b - l1.a, l2.b - l2.a);
    Real b = cross(l1.b - l1.a, l1.b - l2.a);
    if(eq(a, 0.0) and eq(b, 0.0)) {
        res.push_back(l2.a);
    } else {
        res.push_back(l2.a + (l2.b - l2.a) * b / a);
    }
    return res;
}
int main(void) {
    cin.tie(0);
    ios::sync_with_stdio(0);
    int n, m;
    cin >> n >> m;
    vector<vector<Point>> poly(n);
    rep(i, 0, n) {
        int l;
        cin >> l;
        poly[i].resize(l);
        rep(j, 0, l) {
            cin >> poly[i][j];
        }
    }
    vector<Point> ps(m);
    rep(i, 0, m) {
        cin >> ps[i];
    }
    int ans = 1;
    rep(i1, 0, m) {
        rep(i2, i1 + 1, m) {
            rep(j1, 0, n) {
                rep(k1, 0, (int)poly[j1].size()) {
                    rep(j2, 0, n) {
                        rep(k2, 0, (int)poly[j2].size()) {
                            Line l1 = Line(ps[i1], poly[j1][k1]);
                            Line l2 = Line(ps[i2], poly[j2][k2]);
                            vector<Point> inter = intersection_ll(l1, l2);
                            if(inter.empty()) continue;
                            Point cand = inter[0];
                            int cnt = 0;
                            rep(i, 0, m) {
                                Point dir1 = (ps[i] - cand) * EPS;
                                Segment seg1 = Segment(cand + dir1, ps[i] - dir1);
                                bool flag = true;
                                rep(j, 0, n) {
                                    rep(k, 0, (int)poly[j].size()) {
                                        Point dir2 = (poly[j][(k + 1) % poly[j].size()] - poly[j][k]) * EPS;
                                        Segment seg2 = Segment(poly[j][k] + dir2, poly[j][(k + 1) % poly[j].size()] - dir2);
                                        if(is_intersect_ss(seg1, seg2)) {
                                            flag = false;
                                        }
                                    }
                                }
                                if(flag) {
                                    cnt++;
                                }
                            }
                            ans = max(ans, cnt);
                        }
                    }
                }
            }
        }
    }
    cout << ans << '\n';
}
accuracy: 1
time_ms: 90
memory_kb: 3572
final_rank: 2

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

using ll = long long;
using ld = long double;

/*-- library --*/

using Real = long double;
using Point = complex<Real>;
const Real EPS = 1e-9, PI = acos(-1);

inline bool eq(Real a, Real b) {
  return fabs(b - a) < EPS;
}


ostream &operator<<(ostream &os, Point &p) {
  return os << fixed << setprecision(10) << p.real() << " " << p.imag();
}

// a-b-c の角度 (有向角)
Real get_angle(const Point &a, const Point &b, const Point &c) {
  const Point v(b - a), w(c - b);
  Real alpha = arg(v), beta = arg(w);
  Real theta = (- beta + alpha + PI);
  if (theta < 0) theta += 2 * PI;
  if (theta > 2 * PI) theta -= 2 * PI;
  return theta;
}

struct Line {
  Point a, b;

  Line() = default;

  Line(Point a, Point b) : a(a), b(b) {}

  Line(Real A, Real B, Real C)  // Ax + By = C
  {
    if (eq(A, 0)) a = Point(0, C / B), b = Point(1, C / B);
    else if (eq(B, 0)) b = Point(C / A, 0), b = Point(C / A, 1);
    else a = Point(0, C / B), b = Point(C / A, 0);
  }

  friend ostream &operator<<(ostream &os, Line &p) { return os << p.a << " to " << p.b; }

  friend istream &operator>>(istream &is, Line &a) { return is >> a.a >> a.b; }
};

struct Segment : Line {
  Segment() = default;

  Segment(Point a, Point b) : Line(a, b) {}
};


using Points = vector<Point>;
using Polygon = vector<Point>;
using Segments = vector<Segment>;
using Lines = vector<Line>;



Real cross(const Point &a, const Point &b) {
  return real(a) * imag(b) - imag(a) * real(b);
}

Real dot(const Point &a, const Point &b) {
  return real(a) * real(b) + imag(a) * imag(b);
}


// 平行判定
bool parallel(const Line &a, const Line &b) {
  return eq(cross(a.b - a.a, b.b - b.a), 0.0);
}

// 点の回転方向
int ccw(const Point &a, Point b, Point c) {
  b = b - a, c = c - a;
  if (cross(b, c) > EPS) return +1;   // "COUNTER_CLOCKWISE"
  if (cross(b, c) < -EPS) return -1;  // "CLOCKWISE"
  if (dot(b, c) < 0) return +2;       // "ONLINE_BACK"
  if (norm(b) < norm(c)) return -2;   // "ONLINE_FRONT"
  return 0;                           // "ON_SEGMENT"
}

bool intersect(const Segment &s, const Segment &t) {
  return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
         ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}


Point crosspoint(const Line &l, const Line &m) {
  Real A = cross(l.b - l.a, m.b - m.a);
  Real B = cross(l.b - l.a, l.b - m.a);
  if (eq(abs(A), 0.0) && eq(abs(B), 0.0)) return m.a;
  return m.a + (m.b - m.a) * B / A;
}
Point crosspoint(const Segment &l, const Segment &m) {
  return crosspoint(Line(l), Line(m));
}

void solve()
{
    ll N, M; cin >> N >> M;
    
    vector< Polygon > col(N);
    
    for (int i = 0; i < N; ++i)
    {
        ll L; cin >> L;
        for (int j = 0; j < L; ++j)
        {
            ll x, y; cin >> x >> y;
            col[i].emplace_back(Point(x, y));
        }
    }
    
    vector< Point > human(M);
    for (int i = 0; i < M; ++i)
    {
        ll x, y; cin >> x >> y;
        human[i] = Point(x, y);
    }
    
    Segments seg;
    for (int i = 0; i < N; ++i)
    {
        ll L = col[i].size();
        for (int j = 0; j < L; ++j)
        {
            Segment hoge(col[i][j], col[i][(j+1)%L]);
            seg.emplace_back(hoge);
            
            for (int k = 0; k < M; ++k)
            {
                Segment huga(col[i][j], human[k]);
                seg.emplace_back(huga);
            }
        }
    }
    
    
    vector< Polygon > mincol(N);
    for (int i = 0; i < N; ++i)
    {
        ll L = col[i].size();
        
        for (int j = 0; j < L; ++j)
        {
            int pj = (j - 1 + L) % L;
            int nj = (j + 1) % L;
            
            Point dir = (col[i][pj] - col[i][j]) + (col[i][nj] - col[i][j]);
            Real angle = get_angle(col[i][pj], col[i][j], col[i][nj]);
            if (angle > PI) dir *= -1;
            
            dir /= abs(dir);
            Point q = col[i][j] + dir * Point(0.01, 0);
            mincol[i].emplace_back(q);
        }
    }
    
    // for (int i = 0; i < N; ++i)
    // {
    //     ll L = col[i].size();
    //     cout << L << endl;
    //     for (auto p : mincol[i])
    //     {
    //         cout << p << endl;
    //     }
    // }
    
    vector< Point > kouho;
    ll siz = seg.size();
    for (int i = 0; i < siz; ++i)
    {
        for (int j = i+1; j < siz; ++j)
        {
            if (parallel(Line(seg[i]), Line(seg[j]))) continue;
            Point p = crosspoint(seg[i], seg[j]);
            kouho.emplace_back(p);
        }
    }
    
    ll res = 0;
    for (const Point &p : kouho)
    {
        ll tmp = 0;
        for (int i = 0; i < M; ++i)
        {
            Point q = human[i];
            
            Segment eye(p, q);
            bool seen = true;
            
            for (int j = 0; j < N; ++j)
            {
                ll L = col[j].size();
                for (int k = 0; k < L; ++k)
                {
                    Segment hoge(mincol[j][k], mincol[j][(k+1)%L]);
                    seen &=  !intersect(eye, hoge);
                }
            }
            
            if (seen) tmp++;
            else ;
        }
        
        // if (tmp == 2)
        // {
        //     cout << p << endl;
        // }
        
        if (res < tmp) res = tmp;
    }
    cout << res << endl;
    
    return;
}

int main()
{
    solve();
    
    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 3884
final_rank: 11

code_snippet: #line 2 "cp-library/src/cp-template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull  = unsigned long long;
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
template < class T > bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; }
template < class T > bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; }
template < class T, class U > T ceil (T x, U y) { return (x > 0 ? (x + y - 1) / y :           x / y); }
template < class T, class U > T floor(T x, U y) { return (x > 0 ?           x / y : (x - y + 1) / y); }
int popcnt(i32 x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(i64 x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }

#line 2 "cp-library/src/utility/rep_itr.hpp"
template < class T > struct itr_rep {
    T i, d;
    constexpr itr_rep(const T i) noexcept : i(i), d(1) {}
    constexpr itr_rep(const T i, const T d) noexcept : i(i), d(d) {}
    void operator++() noexcept { i += d; }
    constexpr int operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr_rep x) const noexcept { return d > 0 ? i < x.i : i > x.i; }
};

template < class T > struct rep {
    const itr_rep< T > s, t;
    constexpr rep(const T t) noexcept : s(0), t(t) {}
    constexpr rep(const T s, const T t) noexcept : s(s), t(t) {}
    constexpr rep(const T s, const T t, const T d) noexcept : s(s, d), t(t, d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};

template < class T > struct revrep {
    const itr_rep < T > s, t;
    constexpr revrep(const T t) noexcept : s(t - 1, -1), t(-1, -1) {}
    constexpr revrep(const T s, const T t) noexcept : s(t - 1, -1), t(s - 1, -1) {}
    constexpr revrep(const T s, const T t, const T d) noexcept : s(t - 1, -d), t(s - 1, -d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};
#line 3 "cp-library/src/utility/io.hpp"

/* 128bit integer */
istream& operator>>(istream& is, i128& x) {
    std::string s; is >> s;
    int pm = (s[0] == '-');
    x = 0;
    for(int i : rep(pm, int(s.size()))) x = x * 10 + (s[i] - '0');
    if(pm) x *= -1;
    return is;
}
ostream& operator<<(ostream& os, const i128& x) {
    if(x == 0) return os << '0';
    i128 y = x;
    if(y < 0) { os << '-'; y *= -1; }
    std::vector<int> ny;
    while(y > 0) { ny.push_back(y % 10); y /= 10; }
    for(int i : revrep(ny.size())) os << ny[i];
    return os;
}

template < class S, class T > istream& operator>>(istream& is,       std::pair< S, T >& x) { is >> x.first        >> x.second; return is; }
template < class S, class T > ostream& operator<<(ostream& os, const std::pair< S, T >& x) { os << x.first << " " << x.second; return os; }

namespace scanner {
    struct sca {
        template < class T > operator T() {
            T s; std::cin >> s; return s;
        }
    };
    struct vec {
        int n;
        vec(int n) : n(n) {}
        template < class T > operator std::vector< T >() {
            std::vector< T > v(n);
            for(T& x : v) std::cin >> x;
            return v;
        }
    };
    struct mat {
        int h, w;
        mat(int h, int w) : h(h), w(w) {}
        template < class T > operator std::vector< std::vector< T > >() {
            std::vector m(h, std::vector< T >(w));
            for(std::vector< T >& v : m) for(T& x : v) std::cin >> x;
            return m;
        }
    };
    struct speedup {
        speedup() {
            std::cin.tie(0);
            std::ios::sync_with_stdio(0);
        }
    } speedup_instance;
}
scanner::sca in() { return scanner::sca(); }
scanner::vec in(int n) { return scanner::vec(n); }
scanner::mat in(int h, int w) { return scanner::mat(h, w); }

namespace printer {
    void precision(int d) { std::cout << std::fixed << std::setprecision(d); }
    void flush() { std::cout.flush(); }
}

template < class T >
ostream& operator<<(ostream& os, const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) { os << a[i]; if(i != n - 1) os << ' '; }
    return os;
}

int print() { std::cout << '\n'; return 0; }
template < class head, class... tail > int print(head&& h, tail&&... t) {
    std::cout << h; if(sizeof...(tail)) std::cout << ' ';
    return print(std::forward<tail>(t)...);
}
template < class T > int print_n(const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) std::cout << a[i] << "\n";
    return 0;
}


#line 2 "cp-library/src/utility/key_val.hpp"

template < class K, class V >
struct key_val {
    K key; V val;
    key_val() {}
    key_val(K key, V val) : key(key), val(val) {}
    template < std::size_t Index >
    std::tuple_element_t< Index, key_val >& get() {
        if constexpr (Index == 0) return key;
        if constexpr (Index == 1) return val;
    }
};

namespace std {

template < class K, class V > struct tuple_size < key_val< K, V > > : integral_constant< size_t, 2 > {};
template < class K, class V > struct tuple_element < 0, key_val< K, V > > { using type = K; };
template < class K, class V > struct tuple_element < 1, key_val< K, V > > { using type = V; };

}
#line 2 "cp-library/src/utility/vec_op.hpp"
template < class T > key_val< int, T > max_of(const vector< T >& a) {
    int i = std::max_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class T > key_val< int, T > min_of(const vector< T >& a) {
    int i = std::min_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class S, class T > S sum_of(const vector< T >& a) {
    S sum = 0;
    for(const T x : a) sum += x;
    return sum;
}
template < class S, class T > vector< S > freq_of(const vector< T >& a, T L, T R) {
    vector< S > res(R - L, S(0));
    for(const T x : a) res[x - L] += 1;
    return res;
}
template < class S, class T > struct prefix_sum {
    vector< S > s;
    prefix_sum(const vector< T >& a) : s(a) {
        s.insert(s.begin(), S(0));
        for(int i : rep(a.size())) s[i + 1] += s[i];
    }
    // [L, R)
    S sum(int L, int R) { return s[R] - s[L]; }
};
#line 3 "cp-library/src/utility/heap.hpp"

template < class T > using heap_min = std::priority_queue< T, std::vector< T >, std::greater< T > >;
template < class T > using heap_max = std::priority_queue< T, std::vector< T >, std::less< T > >;

#line 27 "cp-library/src/cp-template.hpp"

#line 1 "cp-library/src/algorithm/bin_search.hpp"
template < class T, class F >
T bin_search(T ok, T ng, F f) {
    while(abs(ng - ok) > 1) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

template < class T, class F >
T bin_search_real(T ok, T ng, F f, int step = 80) {
    while(step--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
#line 2 "cp-library/src/algorithm/argsort.hpp"

template < class T > std::vector< int > argsort(const std::vector< T > &a) {
    std::vector< int > ids((int)a.size());
    std::iota(ids.begin(), ids.end(), 0);
    std::sort(ids.begin(), ids.end(), [&](int i, int j) {
        return a[i] < a[j] || (a[i] == a[j] && i < j);
    });
    return ids;
}
#line 1 "macro.hpp"
namespace macro {

using size_type = int;
template < class container > void  sort(container& a) { std::sort(std:: begin(a), std:: end(a)); }
template < class container > void rsort(container& a) { std::sort(std::rbegin(a), std::rend(a)); }
template < class container > void reverse(container& a) { std::reverse(std::begin(a), std::end(a)); }
template < class container > void unique(container& a) {
    std::sort(std::begin(a), std::end(a));
    a.erase(std::unique(std::begin(a), std::end(a)), std::end(a));
}
template < class container > container  sorted(const container& a) { container b = a;  sort(b); return std::move(b); }
template < class container > container rsorted(const container& a) { container b = a; rsort(b); return std::move(b); }
template < class container, class compare > void sort(container& a, const compare& cmp) { std::sort(std::begin(a), std::end(a), cmp); }
template < class container, class compare > container sorted(const container& a, const compare& cmp) { container b = a; sort(b, cmp); return std::move(b); }
template < class container, class value > size_type lower_bound(const container& a, const value& x) { return std::lower_bound(std::begin(a), std::end(a), x) - std::begin(a); }
template < class container, class value > size_type upper_bound(const container& a, const value& x) { return std::upper_bound(std::begin(a), std::end(a), x) - std::begin(a); }

const std::vector<std::pair<size_type, size_type>> dir4 = { {+1,  0}, {-1,  0}, { 0, +1}, { 0, -1} };
const std::vector<std::pair<size_type, size_type>> dir8 = { {-1, -1}, {-1,  0}, {-1, +1}, { 0, -1}, { 0, +1}, {+1, -1}, {+1,  0}, {+1, +1} };

#ifdef _DEBUG
#define debug(x) std::cout << "[" << __LINE__ << "] " << #x << ": " << x << std::endl
#else
#define debug(x)
#endif

template < class container > void concat(container& a, const container& b) {
    a.insert(std::end(a), std::begin(b), std::end(b));
}
std::vector<size_type> iota(const size_type n) {
    std::vector<size_type> I(n);
    std::iota(std::begin(I), std::end(I), 0);
    return I;
}
template < class container > std::vector<size_type> sort_idx(const container& a) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return a[i] < a[j] or (a[i] == a[j] and i < j); });
    return I;
}
template < class container, class compare > std::vector<size_type> sort_idx(const container& a, const compare& cmp) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return cmp(a[i], a[j]) or (a[i] == a[j] and i < j); });
    return std::move(I);
}

struct grid {
    using size_type = int;
    size_type H, W;
    grid(const size_type H, const size_type W) : H(H), W(W) {}
    bool contains(const size_type i, const size_type j) {
        return 0 <= i and i < H and 0 <= j and j < W;
    }
};

using f64 = long double;

} // namespace macro

using namespace macro;
#line 3 "A.cpp"

template < class T > struct point {
    T x, y;
    point() : x(0), y(0) {}
    point(T x, T y) : x(x), y(y) {}
    point(std::pair< T, T > p) : x(p.first), y(p.second) {}
    point& operator+=(const point& p) { x += p.x, y += p.y; return *this; }
    point& operator-=(const point& p) { x -= p.x, y -= p.y; return *this; }
    point& operator*=(const T r) { x *= r, y *= r; return *this; }
    point& operator/=(const T r) { x /= r, y /= r; return *this; }
    point operator+(const point& p) const { return point(*this) += p; }
    point operator-(const point& p) const { return point(*this) -= p; }
    point operator*(const T r) const { return point(*this) *= r; }
    point operator/(const T r) const { return point(*this) /= r; }
    point operator-() const { return {-x, -y}; }
    bool operator==(const point& p) const { return x == p.x and y == p.y; }
    bool operator!=(const point& p) const { return x != p.x or  y != p.y; }
    bool operator<(const point& p) const { return x == p.x ? y < p.y : x < p.x; }
    point< T > rot(double theta) {
        static_assert(is_floating_point_v< T >);
        double cos_ = std::cos(theta), sin_ = std::sin(theta);
        return {cos_ * x - sin_ * y, sin_ * x + cos_ * y};
    }
};
template < class T > istream& operator>>(istream& is, point< T >& p) { return is >> p.x >> p.y; }
template < class T > ostream& operator<<(ostream& os, point< T >& p) { return os << p.x << " " << p.y; }
template < class T > T dot(const point< T >& a, const point< T >& b) { return a.x * b.x + a.y * b.y; }
template < class T > T det(const point< T >& a, const point< T >& b) { return a.x * b.y - a.y * b.x; }
template < class T > T norm(const point< T >& p) { return p.x * p.x + p.y * p.y; }
template < class T > double abs(const point< T >& p) { return std::sqrt(norm(p)); }
template < class T > double angle(const point< T >& p) { return std::atan2(p.y, p.x); }
template < class T > int sign(const T x) {
    T e = (is_integral_v< T > ? 1 : 1e-8);
    if(x <= -e) return -1;
    if(x >= +e) return +1;
    return 0;
}
template < class T > bool equals(const T& a, const T& b) { return sign(a - b) == 0; }
template < class T > int ccw(const point< T >& a, point< T > b, point< T > c) {
    b -= a, c -= a;
    if(sign(det(b, c)) == +1) return +1; // counter clockwise
    if(sign(det(b, c)) == -1) return -1; //         clockwise
    if(sign(dot(b, c)) == -1) return +2; // c-a-b
    if(norm(b) < norm(c)) return -2;     // a-b-c
    return 0;                            // a-c-b
}

template < class T > struct line {
    point< T > a, b;
    line() {}
    line(point< T > a, point< T > b) : a(a), b(b) {}
};
template < class T > point< T > projection(const line< T >& l, const point< T >& p) {
    static_assert(is_floating_point_v< T >);
    return l.a + (l.a - l.b) * dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
}
template < class T > point< T > reflection(const line< T >& l, const point< T >& p) {
    static_assert(is_floating_point_v< T >);
    return p + (projection(l, p) - p) * T(2);
}
template < class T > bool orthogonal(const line< T >& a, const line< T >& b) { return equals(dot(a.b - a.a, b.b - b.a), T(0)); }
template < class T > bool parallel  (const line< T >& a, const line< T >& b) { return equals(det(a.b - a.a, b.b - b.a), T(0)); }
template < class T > point< T > cross_point_ll(const line< T >& l, const line< T >& m) {
    static_assert(is_floating_point_v< T >);
    T A = det(l.b - l.a, m.b - m.a);
    T B = det(l.b - l.a, l.b - m.a);
    if(equals(abs(A), T(0)) and equals(abs(B), T(0))) return m.a;
    return m.a + (m.b - m.a) * B / A;
}

template < class T > using segment = line< T >;
template < class T > bool intersect_ss(const segment< T >& s, const segment< T >& t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) < 0 and ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) < 0;
}
template < class T > double distance_sp(const segment< T >& s, const point< T >& p) {
    static_assert(is_floating_point_v< T >);
    point r = projection(s, p);
    if(ccw(s.a, s.b, r) == 0) return abs(r - p);
    return std::min(abs(s.a - p), abs(s.b - p));
}
template < class T > double distance_ss(const segment< T >& a, const segment< T >& b) {
    if(intersect_ss(a, b)) return 0;
    return std::min({ distance_sp(a, b.a), distance_sp(a, b.b), distance_sp(b, a.a), distance_sp(b, a.b) });
}

template < class T > using polygon = std::vector< point< T > >;
template < class T > T area2(const polygon< T >& p) {
    T s = 0;
    int n = p.size();
    for(int i = 0; i < n; i++) s += det(p[i], p[(i + 1) % n]);
    return s;
}
template < class T > T area(const polygon< T >& p) { return area2(p) / T(2); }

template < class T > bool is_convex(const polygon< T >& p) {
    int n = p.size();
    for(int i = 0; i < n; i++) if(ccw(p[(i - 1 + n) % n], p[i], p[(i + 1) % n]) == -1) return false;
    return true;
}
template < class T > int contains(const polygon< T >& g, const point< T >& p) {
    int n = g.size();
    bool in = false;
    for(int i = 0; i < n; i++) {
        point a = g[i] - p, b = g[(i + 1) % n] - p;
        if(sign(a.y - b.y) == +1) std::swap(a, b);
        if(sign(a.y) <= 0 and sign(b.y) ==+1 and sign(det(a, b)) == -1) in = !in;
        if(sign(det(a, b)) == 0 and sign(dot(a, b)) <= 0) return 1; // ON
    }
    return in ? 2 : 0;
}
template < class T > polygon< T > convex_cut(const polygon< T >& p, const line< T >& l) {
    int n = p.size();
    polygon< T > res;
    for(int i = 0; i < n; i++) {
        point now = p[i], nxt = p[(i + 1) % n];
        if(ccw(l.a, l.b, now) != -1) res.push_back(now);
        if(ccw(l.a, l.b, now) * ccw(l.a, l.b, nxt) < 0) res.push_back(cross_point_ll(line(now, nxt), l));
    }
    return res;
}
template < class T > polygon< T > convex_hull(polygon< T >& p) {
    int n = p.size(), k = 0;
    if(n <= 2) return p;
    std::sort(p.begin(), p.end());
    polygon< T > ch(n + n);
    for(int i = 0; i < n; ch[k++] = p[i++])
        while(k >= 2 and sign(det(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1])) == -1) k--;
    for(int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--])
        while(k >= t and sign(det(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1])) == -1) k--;
    ch.resize(k - 1);
    return ch;
}
template < class T > T diameter2(const polygon< T >& p) {
    static_assert(is_floating_point_v< T >);
    int n = p.size(), is = 0, js = 0;
    for(int i = 1; i < n; i++) {
        if(sign(p[i].y - p[is].y) == +1) is = i;
        if(sign(p[i].y - p[js].y) == -1) js = i;
    }
    T dist_max = norm(p[is] - p[js]);
    int maxi = is, i = is, maxj = js, j = js;
    do {
        if(sign(det(p[(i + 1) % n] - p[i], p[(j + 1) % n] - p[j])) >= 0) j = (j + 1) % n; else i = (i + 1) % n;
        if(norm(p[i] - p[j]) > dist_max) {
            dist_max = norm(p[i] - p[j]);
            maxi = i, maxj = j;
        }
    } while(i != is or j != js);
    return dist_max;
}
template < class T > double diameter(const polygon< T >& p) {
    static_assert(is_floating_point_v< T >);
    return std::sqrt(diameter2(p));
}

template < class T > struct circle {
    point< T > p;
    T r;
    circle() = default;
    circle(point< T > p, T r) : p(p), r(r) {}
};
template < class T > istream& operator>>(istream& is, circle< T >& c) { return is >> c.p >> c.r; }
template < class T > int intersect_cc(circle< T > c1, circle< T > c2) {
    if(c1.r < c2.r) std::swap(c1, c2);
    T d = abs(c1.p - c2.p);
    if(sign(c1.r + c2.r - d) == -1) return 4;
    if(equals(c1.r + c2.r, d)) return 3;
    if(sign(c1.r - c2.r - d) == -1) return 2;
    if(equals(c1.r - c2.r, d)) return 1;
    return 0;
}
template < class T > std::pair<point< T >, point< T >> cross_point_cc(const circle< T >& c1, const circle< T >& c2) {
    T d = abs(c1.p - c2.p);
    T a = std::acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
    T t = angle(c2.p - c1.p);
    point< T > p1 = c1.p + point< T >(std::cos(t + a), std::sin(t + a)) * c1.r;
    point< T > p2 = c1.p + point< T >(std::cos(t - a), std::sin(t - a)) * c1.r;
    return {p1, p2};
}

int main() {
    int N = in(), M = in();
    vector<polygon<f64>> P(N);
    vector<point<f64>> ps;
    for(int i : rep(N)) {
        int L = in();
        P[i] = in(L);
        ps.insert(ps.end(), P[i].begin(), P[i].end());
    }
    vector<point<f64>> Q = in(M);

    int ans = 1;
    const int K = ps.size();
    for(int pi : rep(K)) for(int pj : rep(K)) {
        for(int qi : rep(M)) for(int qj : rep(M)) {
            line<f64> li(ps[pi], Q[qi]);
            line<f64> lj(ps[pj], Q[qj]);
            if(parallel(li, lj)) continue;
            point<f64> X = cross_point_ll(li, lj);

            int cnt = 0;
            for(int i : rep(M)) {
                segment<f64> s(X, Q[i]);
                bool ok = [&] {
                    for(int i : rep(N)) {
                        const int L = P[i].size();
                        for(int k : rep(L)) {
                            segment<f64> p(P[i][k], P[i][(k + 1) % L]);
                            if(intersect_ss(s, p)) return false;
                        }
                    }
                    return true;
                }();
                if(ok) cnt++;
            }
            chmax(ans, cnt);
        }
    }

    print(ans);
}
accuracy: 1
time_ms: 40
memory_kb: 3540
final_rank: 1

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

const long double EPS = 1.0e-9L;
const long double PI = 3.14159265358979L;

// ============================================================= Geometry Library =============================================================
struct Point {
    long double px, py;
};

Point operator+(const Point &a1, const Point &a2) {
    return Point{ a1.px + a2.px, a1.py + a2.py };
}

Point operator-(const Point &a1, const Point &a2) {
    return Point{ a1.px - a2.px, a1.py - a2.py };
}

Point operator*(const Point &a1, const long double &a2) {
    return Point{ a1.px * a2, a1.py * a2 };
}

long double crs(Point a1, Point a2) {
    return a1.px * a2.py - a1.py * a2.px;
}

bool parallel(Point a1, Point a2) {
    if (fabs(crs(a1, a2)) < EPS) return true;
    return false;
}

Point cross_point(Point a1, Point a2, Point b1, Point b2) {
    long double v1 = crs(a2 - a1, b1 - a1);
    long double v2 = crs(a2 - a1, b2 - a1);
    long double wari = (0.0L - v1) / (v2 - v1);
    return b1 + (b2 - b1) * wari;
}

bool intersect(Point a1, Point a2, Point b1, Point b2) {
    long double v1 = crs(a2 - a1, b1 - a1);
    long double v2 = crs(a2 - a1, b2 - a1);
    long double w1 = crs(b2 - b1, a1 - b1);
    long double w2 = crs(b2 - b1, a2 - b1);
    int cnt = 0;
    if (v1 > +EPS && v2 < -EPS) cnt += 1;
    if (v2 > +EPS && v1 < -EPS) cnt += 1;
    if (w1 > +EPS && w2 < -EPS) cnt += 1;
    if (w2 > +EPS && w1 < -EPS) cnt += 1;
    if (cnt == 2) return true;
    return false;
}

// ============================================================= Main Part =============================================================
int N; vector<Point> Poly[19], Poly2[19];
int M; Point U[19];

vector<Point> Small(vector<Point> G) {
    vector<Point> Return;
    for (int i = 0; i < (int)G.size(); i++) {
        Point v1 = G[(i + G.size() - 1) % G.size()];
        Point v2 = G[i];
        Point v3 = G[(i + 1) % G.size()];
        long double angle1 = atan2l((v2 - v1).py, (v2 - v1).px);
        long double angle2 = atan2l((v3 - v2).py, (v3 - v2).px); if (angle1 > angle2) angle2 += 2.0L * PI;
        long double base = (angle1 + angle2 + PI) / 2.0L;
        Point H = G[i] + Point{ 1.0e-7L * cos(base), 1.0e-7L * sin(base) };
        Return.push_back(H);
    }
    return Return;
}

bool check(Point S, Point T) {
    for (int i = 1; i <= N; i++) {
        for (int j = 0; j < Poly2[i].size(); j++) {
            Point J1 = Poly2[i][j];
            Point J2 = Poly2[i][(j + 1) % Poly2[i].size()];
            bool ret = intersect(S, T, J1, J2);
            if (ret == true) return false;
        }
    }
    return true;
}

int main() {
    // Step 1. Input
    cin >> N >> M;
    for (int i = 1; i <= N; i++) {
        int cnt; cin >> cnt;
        Poly[i].resize(cnt);
        for (int j = 0; j < cnt; j++) cin >> Poly[i][j].px >> Poly[i][j].py;
    }
    for (int i = 1; i <= M; i++) cin >> U[i].px >> U[i].py;

    // Step 2. Get Little-bit Small Polygon
    for (int i = 1; i <= N; i++) {
        Poly2[i] = Small(Poly[i]);
    }

    // Step 3. Enumerate Line
    vector<pair<Point, Point>> CandLine;
    vector<Point> CandPoint;
    for (int i = 1; i <= N; i++) {
        for (Point base : Poly[i]) {
            CandPoint.push_back(base);
            for (int j = 1; j <= M; j++) CandLine.push_back(make_pair(U[j], base));
        }
    }
    
    // Step 4. Enumerate Point
    for (int i = 0; i < (int)CandLine.size(); i++) {
        for (int j = i + 1; j < (int)CandLine.size(); j++) {
            Point p1 = CandLine[i].first;
            Point p2 = CandLine[i].second;
            Point q1 = CandLine[j].first;
            Point q2 = CandLine[j].second;
            if (parallel(p2 - p1, q2 - q1) == true) continue;
            Point v = cross_point(p1, p2, q1, q2);
            CandPoint.push_back(v);
        }
    }

    // Step 5. Get Answer
    int Answer = 0;
    for (int i = 0; i < CandPoint.size(); i++) {
        int cnt = 0;
        for (int j = 1; j <= M; j++) {
            bool ret = check(CandPoint[i], U[j]);
            if (ret == true) cnt += 1;
        }
        // cout << "! " << CandPoint[i].px << " " << CandPoint[i].py << " " << cnt << endl;
        Answer = max(Answer, cnt);
    }

    // Step 6. Output
    cout << Answer << endl;
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 4340
final_rank: 13

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

using ll = long long;
#define REP(i, n) for (int i = 0; i < (n); i++)
template <class T> using V = vector<T>;

template <class T> ostream& operator<<(ostream& os, const V<T>& v) {
    os << "[ ";
    for (auto &vi : v) os << vi << ", ";
    return os << "]";
}

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

#ifdef LOCAL
#define show(x) cerr << __LINE__ << " : " << #x << " = " << x << endl;
#else
#define show(x) true
#endif

template <typename T> struct Point {
    static T EPS;
    static constexpr T PI = 3.1415926535'8979323846'2643383279L;
    static void set_eps(const T& e) { EPS = e; }
    T x, y;
    Point(const T x = T(0), const T y = T(0)) : x(x), y(y) {}
    Point& operator+=(const Point& p) {
        x += p.x;
        y += p.y;
        return *this;
    }
    Point& operator-=(const Point& p) {
        x -= p.x;
        y -= p.y;
        return *this;
    }
    Point& operator*=(const T& k) {
        x *= k;
        y *= k;
        return *this;
    }
    friend Point operator+(const Point& a, const Point& b) { return Point(a) += b; }
    friend Point operator-(const Point& a, const Point& b) { return Point(a) -= b; }
    friend Point operator*(const Point& p, const T& k) { return Point(p) *= k; }
    friend istream& operator>>(istream& is, Point& p) { return is >> p.x >> p.y; }
    friend ostream& operator<<(ostream& os, const Point& p) { return os << "(" << p.x << ", " << p.y << ")"; }
};

template <typename T> inline int sign(const T& x) { return x < -Point<T>::EPS ? -1 : x > Point<T>::EPS ? 1 : 0; }
template <typename T> inline bool equal(const T& a, const T& b) { return sign(a - b) == 0; }

template <typename T> inline bool equal(const Point<T>& a, const Point<T>& b) { return equal(a.x, b.x) and equal(a.y, b.y); }
template <typename T> inline T dot(const Point<T>& a, const Point<T>& b) { return a.x * b.x + a.y * b.y; }
template <typename T> inline T cross(const Point<T>& a, const Point<T>& b) { return a.x * b.y - a.y * b.x; }
template <typename T> inline T norm(const Point<T>& p) { return p.x * p.x + p.y * p.y; }

template <> double Point<double>::EPS = 1e-9;

template <typename T> struct Line {
    Point<T> a, b;

    Line() = default;

    Line(const Point<T>& a, const Point<T>& b) : a(a), b(b) {}
};

template <typename T> struct Segment : Line<T> {
    Segment() = default;

    Segment(const Point<T>& a, const Point<T>& b) : Line<T>(a, b) {}
};

constexpr int COUNTER_CLOCKWISE = 1;
constexpr int CLOCKWISE = -1;
constexpr int ONLINE_BACK = 2;
constexpr int ONLINE_FRONT = -2;
constexpr int ON_SEGMENT = 0;

template <typename T> int ccw(const Point<T>& a, Point<T> b, Point<T> c) {
    b = b - a, c = c - a;
    if (sign(cross(b, c)) == 1) return COUNTER_CLOCKWISE;
    if (sign(cross(b, c)) == -1) return CLOCKWISE;
    if (sign(dot(b, c)) == -1) return ONLINE_BACK;
    if (norm(b) < norm(c)) return ONLINE_FRONT;
    return ON_SEGMENT;
}

template <typename T> bool is_intersect_ll(const Line<T>& l1, const Line<T>& l2) {
    Point base = l1.b - l1.a;
    T d12 = cross(base, l2.b - l2.a);
    T d1 = cross(base, l1.b - l2.a);
    if (sign(d12) == 0) {
        if (sign(d1) == 0) {
            return true;
        } else {
            return false;
        }
    }
    return true;
}

template <typename T> Point<T> cross_point_ll(const Line<T>& l1, const Line<T>& l2) {
    Point base = l1.b - l1.a;
    T d12 = cross(base, l2.b - l2.a);
    T d1 = cross(base, l1.b - l2.a);
    if (sign(d12) == 0) {
        if (sign(d1) == 0) {
            return l2.a;
        } else {
            assert(false);
        }
    }
    return l2.a + (l2.b - l2.a) * (d1 / d12);
}

template <typename T> inline bool is_intersect_ss(const Segment<T>& s1, const Segment<T>& s2) {
    return ccw(s1.a, s1.b, s2.a) * ccw(s1.a, s1.b, s2.b) < 0 and ccw(s2.a, s2.b, s1.a) * ccw(s2.a, s2.b, s1.b) < 0;
}

int main() {
    int N, M;
    cin >> N >> M;
    using D = double;
    using P = Point<D>;
    vector<vector<P>> ps(N);
    vector<P> pv;
    REP(i, N) {
        int L;
        cin >> L;
        REP(j, L) {
            P p;
            cin >> p;
            ps[i].push_back(p);
            pv.push_back(p);
        }
    }
    vector<P> xy(M);
    REP(i, M) cin >> xy[i];
    vector<P> can;
    for (auto& pc1 : xy) {
        for (auto& pc2 : xy) {
            for (auto& pv1 : pv) {
                for (auto& pv2 : pv) {
                    if (equal(pc1, pc2) and equal(pv1, pv2)) continue;
                    if (!is_intersect_ll(Line<D>(pc1, pv1), Line<D>(pc2, pv2))) continue;
                    auto cp = cross_point_ll(Line<D>(pc1, pv1), Line<D>(pc2, pv2));
                    can.push_back(cp);
                }
            }
        }
    }
    int ans = 1;
    for (auto& cp : can) {
        int cnt = 0;
        for (auto& cc : xy) {
            int ok = 1;
            for (auto& poly : ps) {
                int K = int(poly.size());
                REP(i, K) {
                    if (is_intersect_ss(Segment<D>(cp, cc), Segment<D>(poly[i], poly[(i + 1) % K]))) {
                        ok = 0;
                    }
                }
            }
            cnt += ok;
        }
        ans = max(ans, cnt);
    }
    cout << ans << '\n';
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3848
final_rank: 8

code_snippet: #include<bits/stdc++.h>
#define rep(i,s,n) for (int i = (int)(s); i < (int)(n); i++)
#define rrep(i,s,n) for (int i = (int)(n)-1; i >= (int)(s); i--)
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
const int INF = 1001001001;

template<typename T> bool chmin(T &a, const T &b){
    if (a <= b) return false;
    a = b;
    return true;
}
template<typename T> bool chmax(T &a, const T &b){
    if (a >= b) return false;
    a = b;
    return true;
}


using pdd = pair<ld,ld>;
const ld c1 = cosl(0.001);
const ld s1 = sinl(0.001);
const ld eps = 1e-7;

ld det(pdd pa, pdd pb){
    return pa.first * pb.second - pa.second * pb.first;
}
int isp(pdd pa, pdd pb, pdd pc){
    pdd d = pdd(pb.first - pa.first, pb.second - pa.second);
    pdd e = pdd(pc.first - pa.first, pc.second - pa.second);
    ld x = det(d, e);
    if (abs(x) < eps) return 0;
    if(x < 0) return -1;
    if(x > 0) return 1;
    return 0;
}
bool crosss(pdd pa, pdd pb, pdd pc, pdd pd){
    return isp(pa,pb,pc) * isp(pa,pb,pd) < 0 && isp(pc,pd,pa) * isp(pc,pd,pb) < 0;
}

void rot(pdd &a){
    ld nx = a.first * c1 - a.second * s1;
    ld ny = a.first * s1 + a.second * c1;
    a = pdd(nx,ny);
}

int main(){
    int n, m; cin >> n >> m;
    vector<vector<pdd>> a(n);
    rep(i,0,n){
        int l; cin >> l;
        a[i].resize(l);
        rep(j,0,l){
            ld x, y; cin >> x >> y;
            a[i][j] = pdd(x,y);
        }
    }
    vector<pdd> b(m);
    rep(i,0,m){
        ld x, y; cin >> x >> y;
        b[i] = pdd(x,y);
    }
    rep(i,0,n){
        for (auto &p : a[i]) rot(p);
    }
    rep(j,0,m) rot(b[j]);
    vector<pdd> lines;
    rep(i,0,n) for (auto p : a[i]) rep(j,0,m){
        ld r = (p.second - b[j].second) / (p.first - b[j].first);
        ld d = b[j].second - b[j].first * r;
        lines.emplace_back(r,d);
    }
    vector<pdd> ps;
    int siz = lines.size();
    rep(i,0,siz-1) rep(j,i+1,siz){
        ld r1 = lines[i].first, d1 = lines[i].second;
        ld r2 = lines[j].first, d2 = lines[j].second;
        if (abs(r1-r2) < eps) continue;
        ld x = (d2-d1) / (r1-r2);
        ld y = r1*x+d1;
        ps.emplace_back(x,y);
    }
    siz = ps.size();
    int ans = 0;
    rep(i,0,siz){
        int cnt = 0;
        rep(j,0,m){
            bool ok = true;
            rep(k,0,n){
                int sk = a[k].size();
                rep(l,0,sk){
                    pdd a0 = a[k][l], b0 = a[k][(l+1)%sk];
                    if (crosss(a0,b0,ps[i],b[j])) ok = false;
                }
            }
            if (ok) cnt++;
        }
        chmax(ans,cnt);
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 30
memory_kb: 3828
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using i32 = int;
using pii = pair<i32, i32>;
struct line {
	pii a, b;
	line(pii a, pii b) : a(a), b(b) {}
};

pii diff(pii a, const pii& b) {
	a.first -= b.first;
	a.second -= b.second;
	return a;
}

i32 cross(const pii& a, const pii& b) {
	return a.first * b.second - a.second * b.first;
}

i32 dot(const pii& a, const pii& b) {
	return a.first * b.first + a.second * b.second;
}

i32 sgn(i32 v) {
	return (v < 0 ? -1 : (v == 0 ? 0 : 1));
}

i32 norm(const pii& a) {
	return a.first * a.first + a.second + a.second;
}

i32 ccw(const pii& a, const pii& b) {
	i32 outer = sgn(cross(a, b));
	if (outer == 1) return 1;
	if (outer == -1) return -1;
	if (sgn(dot(a, b)) == -1) return 2;
	if (norm(a) < norm(b)) return -2;
	return 0;
}

bool intersect(const line& l1, const line& l2) {
	pii a = diff(l1.b, l1.a), b = diff(l2.b, l2.a);
	return ccw(a, diff(l2.a, l1.a)) * ccw(a, diff(l2.b, l1.a)) <= 0
		and
		ccw(b, diff(l1.a, l2.a)) * ccw(b, diff(l1.b, l2.a)) <= 0;
}

void input(pair<i32, i32>& p) {
	cin >> p.first >> p.second;
	p.first *= 50;
	p.second *= 50;
}

int main() {
	i32 n, m; cin >> n >> m;
	vector<vector<pii>> B(n);
	for (i32 i = 0 ; i < n ; i++) {
		i32 L; cin >> L;
		B[i] = vector(L, pii());
		for (auto& p : B[i]) input(p);
	}
	vector P(m, pii());
	for (auto& p : P) input(p);
	i32 ans = 1;
	for (i32 i = -2000 ; i <= 2000 ; i++) {
		for (i32 j = -2000 ; j <= 2000 ; j++) {
			i32 v = 0;
			for (i32 k = 0 ; k < m ; k++) {
				bool ok = true;
				const line p(pair(i, j), P[k]);
				for (i32 bi = 0 ; bi < n ; bi++) {
					for (i32 bj = 0 ; bj < (i32)B[bi].size() ; bj++) {
						const line q(B[bi][bj], B[bi][(bj + 1) % B[bi].size()]);
						ok &= !intersect(p, q);
					}
				}
				v += ok;
			}
			ans = max(ans, v);
		}
	}
	cout << ans << endl;
}
accuracy: 0.06521739130434782
time_ms: 5050
memory_kb: 3444
final_rank: 20

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

// {{{ Templates

// clang-format off

// Macros
#define over_load_(_1,_2,_3,_4,NAME,...) NAME
#define rep(...) over_load_(__VA_ARGS__, rep4, rep3, rep2)(__VA_ARGS__)
#define rep2(i, r) for ( int i = 0; i < static_cast<int>(r); (i) += 1)
#define rep3(i, l, r) for ( int i = static_cast<int>(l); i < static_cast<int>(r); (i) += 1)
#define rep4(i, l, r, stride) for ( int i = static_cast<int>(l); i < static_cast<int>(r); (i) += (stride))
#define rrep(...) over_load_(__VA_ARGS__, rrep4, rrep3, rrep2)(__VA_ARGS__)
#define rrep2(i, r) for ( int i = static_cast<int>(r) - 1; i >= 0; (i) -= 1)
#define rrep3(i, l, r) for ( int i = static_cast<int>(r) - 1; i >= static_cast<int>(l); (i) -= 1)
#define rrep4(i, l, r, stride) for ( int i = static_cast<int>(r) - 1; i >= static_cast<int>(l); (i) -= (stride))
#define len(x) (static_cast<int>((x).size()))
#define whole(f, x, ...) ([&](decltype((x)) container) { return (f)( begin(container), end(container), ## __VA_ARGS__); })(x)
#define rwhole(f, x, ...) ([&](decltype((x)) container) { return (f)( rbegin(container), rend(container), ## __VA_ARGS__); })(x)
#define debug(...) debug_function(#__VA_ARGS__, __VA_ARGS__)

// Operators
template <typename T1, typename T2> ostream &operator<<(ostream &os, const pair<T1, T2> &p) { os << "(" << p.first << "," << p.second << ")"; return os; }
template <typename T1, typename T2> ostream &operator<<(ostream &os, const map<T1, T2> &v) { bool is_first = true; for (auto x: v) { os << (is_first ? "" : " ") << x; is_first = false; } return os; }
template <typename T> ostream &operator<<(ostream &os, queue<T> v) { bool is_first = true; while (!v.empty()) { os << (is_first?"":" ")<<v.front(); v.pop(); is_first = false; } return os; }
template <typename T> ostream &operator<<(ostream &os, stack<T> v) { bool is_first = true; while (!v.empty()) { os << (is_first?"":" ") << v.top(); v.pop(); is_first=false; } return os; }
template <typename T> ostream &operator<<(ostream &os, const vector<T> &v) { rep (i, len(v)) os << v[i] << (i == len(v) - 1 ? "" : " "); return os; }
template <typename T> ostream &operator<<(ostream &os, const vector<vector<T>> &v) { for (const auto &vec: v) { os << vec << '\n'; } return os; }
template <typename T> ostream &operator<<(ostream &os, const deque<T> &v) { rep (i, len(v)) os << v[i] << (i == len(v) - 1 ? "" : " "); return os; }
template <typename T> ostream &operator<<(ostream &os, const set<T> &v) { bool is_first = true; for (T x: v) { os << (is_first ? "" : " ") << x; is_first = false; } return os; }
template <typename T> istream &operator>>(istream &is, vector<T> &v) { for (T &in: v) { is >> in; } return is; }

// For debug macro
int find_comma_not_bracketed(string_view s){ stack<char> bs; string lbs = "({[", rbs = ")}]"; for (size_t i = 0; i < s.size(); i++) { if (lbs.find(s[i]) != string::npos) bs.push(s[i]); if (rbs.find(s[i]) != string::npos and !bs.empty()) bs.pop(); if (s[i] == ',' and bs.empty()) return i; } return s.size(); }
template <typename T, typename... Ts> void debug_function(string_view name, const T &a, Ts &&...rest) { int end = find_comma_not_bracketed(name); cerr << name.substr(0, end) << ":" << a; if constexpr (sizeof...(rest) == 0) { cerr << '\n'; } else { cerr << ' '; debug_function(name.substr(name.find_first_not_of(' ', end + 1)), forward<Ts>(rest)...); } }

// Functions
template <typename T> vector<T> make_vector(size_t a, T b) { return vector<T>(a, b); }
template <typename... Ts> auto make_vector(size_t a, Ts... ts) { return vector<decltype(make_vector(ts...))>(a, make_vector(ts...)); }
template <typename T1, typename T2> inline bool chmax(T1 &a, T2 b) { return a < b and (a = b, true); }
template <typename T1, typename T2> inline bool chmin(T1 &a, T2 b) { return a > b and (a = b, true); }

// Structs
struct IoSetup { IoSetup(int x = 15) { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(x); cerr << fixed << setprecision(x); } } iosetup;

// Type aliases
using ull = unsigned long long;
using ll = long long;
using pll = pair<ll, ll>;
using pii = pair<int, int>;

// Literals
constexpr ll INF64 = INT64_MAX / 2;
constexpr int INF32 = INT32_MAX / 2;
constexpr int dy[] = { 0, 1, -1, 0, -1, 1, -1, 1 };
constexpr int dx[] = { 1, 0, 0, -1, -1, -1, 1, 1 };
constexpr int mod998244353 = 998244353;
constexpr int mod1000000007 = static_cast<int>(1e9) + 7;
constexpr char newl = '\n';

// clang-format on

// }}} Templates

using Real = double;
using Point = complex<Real>;
const Real EPS = 1e-8, PI = acos(-1);

inline bool eq(Real a, Real b) {
  return fabs(b - a) < EPS;
}

Point operator*(const Point &p, const Real &d) {
  return Point(real(p) * d, imag(p) * d);
}

istream &operator>>(istream &is, Point &p) {
  Real a, b;
  is >> a >> b;
  p = Point(a, b);
  return is;
}

ostream &operator<<(ostream &os, Point &p) {
  return os << fixed << setprecision(10) << p.real() << " " << p.imag();
}

// 点 p を反時計回りに theta 回転
Point rotate(Real theta, const Point &p) {
  return Point(cos(theta) * p.real() - sin(theta) * p.imag(), sin(theta) * p.real() + cos(theta) * p.imag());
}

Real radian_to_degree(Real r) {
  return (r * 180.0 / PI);
}

Real degree_to_radian(Real d) {
  return (d * PI / 180.0);
}

// a-b-c の角度のうち小さい方を返す
Real get_angle(const Point &a, const Point &b, const Point &c) {
  const Point v(b - a), w(c - b);
  Real alpha = atan2(v.imag(), v.real()), beta = atan2(w.imag(), w.real());
  if (alpha > beta)
    swap(alpha, beta);
  Real theta = (beta - alpha);
  return min(theta, 2 * acos(-1) - theta);
}

namespace std {
  bool operator<(const Point &a, const Point &b) {
    return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
  }
} // namespace std


struct Line {
  Point a, b;

  Line() = default;

  Line(Point a, Point b): a(a), b(b) {}

  Line(Real A, Real B, Real C) // Ax + By = C
  {
    if (eq(A, 0))
      a = Point(0, C / B), b = Point(1, C / B);
    else if (eq(B, 0))
      b = Point(C / A, 0), b = Point(C / A, 1);
    else
      a = Point(0, C / B), b = Point(C / A, 0);
  }

  friend ostream &operator<<(ostream &os, Line &p) {
    return os << p.a << " to " << p.b;
  }

  friend istream &operator>>(istream &is, Line &a) {
    return is >> a.a >> a.b;
  }
};

struct Segment: Line {
  Segment() = default;

  Segment(Point a, Point b): Line(a, b) {}
};

struct Circle {
  Point p;
  Real r;

  Circle() = default;

  Circle(Point p, Real r): p(p), r(r) {}
};

using Points = vector<Point>;
using Polygon = vector<Point>;
using Segments = vector<Segment>;
using Lines = vector<Line>;
using Circles = vector<Circle>;

Real cross(const Point &a, const Point &b) {
  return real(a) * imag(b) - imag(a) * real(b);
}

Real dot(const Point &a, const Point &b) {
  return real(a) * real(b) + imag(a) * imag(b);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_C
// 点の回転方向
int ccw(const Point &a, Point b, Point c) {
  b = b - a, c = c - a;
  if (cross(b, c) > EPS)
    return +1; // "COUNTER_CLOCKWISE"
  if (cross(b, c) < -EPS)
    return -1; // "CLOCKWISE"
  if (dot(b, c) < 0)
    return +2; // "ONLINE_BACK"
  if (norm(b) < norm(c))
    return -2; // "ONLINE_FRONT"
  return 0;    // "ON_SEGMENT"
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
// 平行判定
bool parallel(const Line &a, const Line &b) {
  return eq(cross(a.b - a.a, b.b - b.a), 0.0);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
// 垂直判定
bool orthogonal(const Line &a, const Line &b) {
  return eq(dot(a.a - a.b, b.a - b.b), 0.0);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_A
// 射影
// 直線 l に p から垂線を引いた交点を求める
Point projection(const Line &l, const Point &p) {
  double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
  return l.a + (l.a - l.b) * t;
}

Point projection(const Segment &l, const Point &p) {
  double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
  return l.a + (l.a - l.b) * t;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_B
// 反射
// 直線 l を対称軸として点 p  と線対称にある点を求める
Point reflection(const Line &l, const Point &p) {
  return p + (projection(l, p) - p) * 2.0;
}

bool intersect(const Line &l, const Point &p) {
  return abs(ccw(l.a, l.b, p)) != 1;
}

bool intersect(const Line &l, const Line &m) {
  return abs(cross(l.b - l.a, m.b - m.a)) > EPS || abs(cross(l.b - l.a, m.b - l.a)) < EPS;
}

bool intersect(const Segment &s, const Point &p) {
  return ccw(s.a, s.b, p) == 0;
}

bool intersect(const Line &l, const Segment &s) {
  return cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < EPS;
}

Real distance(const Line &l, const Point &p);

bool intersect(const Circle &c, const Line &l) {
  return distance(l, c.p) <= c.r + EPS;
}

bool intersect(const Circle &c, const Point &p) {
  return abs(abs(p - c.p) - c.r) < EPS;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_B
bool intersect(const Segment &s, const Segment &t) {
  return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

int intersect(const Circle &c, const Segment &l) {
  if (norm(projection(l, c.p) - c.p) - c.r * c.r > EPS)
    return 0;
  auto d1 = abs(c.p - l.a), d2 = abs(c.p - l.b);
  if (d1 < c.r + EPS && d2 < c.r + EPS)
    return 0;
  if (d1 < c.r - EPS && d2 > c.r + EPS || d1 > c.r + EPS && d2 < c.r - EPS)
    return 1;
  const Point h = projection(l, c.p);
  if (dot(l.a - h, l.b - h) < 0)
    return 2;
  return 0;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_A&lang=jp
int intersect(Circle c1, Circle c2) {
  if (c1.r < c2.r)
    swap(c1, c2);
  Real d = abs(c1.p - c2.p);
  if (c1.r + c2.r < d)
    return 4;
  if (eq(c1.r + c2.r, d))
    return 3;
  if (c1.r - c2.r < d)
    return 2;
  if (eq(c1.r - c2.r, d))
    return 1;
  return 0;
}

Real distance(const Point &a, const Point &b) {
  return abs(a - b);
}

Real distance(const Line &l, const Point &p) {
  return abs(p - projection(l, p));
}

Real distance(const Line &l, const Line &m) {
  return intersect(l, m) ? 0 : distance(l, m.a);
}

Real distance(const Segment &s, const Point &p) {
  Point r = projection(s, p);
  if (intersect(s, r))
    return abs(r - p);
  return min(abs(s.a - p), abs(s.b - p));
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_D
Real distance(const Segment &a, const Segment &b) {
  if (intersect(a, b))
    return 0;
  return min({ distance(a, b.a), distance(a, b.b), distance(b, a.a), distance(b, a.b) });
}

Real distance(const Line &l, const Segment &s) {
  if (intersect(l, s))
    return 0;
  return min(distance(l, s.a), distance(l, s.b));
}

Point crosspoint(const Line &l, const Line &m) {
  Real A = cross(l.b - l.a, m.b - m.a);
  Real B = cross(l.b - l.a, l.b - m.a);
  if (eq(abs(A), 0.0) && eq(abs(B), 0.0))
    return m.a;
  return m.a + (m.b - m.a) * B / A;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_C
Point crosspoint(const Segment &l, const Segment &m) {
  return crosspoint(Line(l), Line(m));
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_D
pair<Point, Point> crosspoint(const Circle &c, const Line l) {
  Point pr = projection(l, c.p);
  Point e = (l.b - l.a) / abs(l.b - l.a);
  if (eq(distance(l, c.p), c.r))
    return { pr, pr };
  double base = sqrt(c.r * c.r - norm(pr - c.p));
  return { pr - e * base, pr + e * base };
}

pair<Point, Point> crosspoint(const Circle &c, const Segment &l) {
  Line aa = Line(l.a, l.b);
  if (intersect(c, l) == 2)
    return crosspoint(c, aa);
  auto ret = crosspoint(c, aa);
  if (dot(l.a - ret.first, l.b - ret.first) < 0)
    ret.second = ret.first;
  else
    ret.first = ret.second;
  return ret;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_E
pair<Point, Point> crosspoint(const Circle &c1, const Circle &c2) {
  Real d = abs(c1.p - c2.p);
  Real a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
  Real t = atan2(c2.p.imag() - c1.p.imag(), c2.p.real() - c1.p.real());
  Point p1 = c1.p + Point(cos(t + a) * c1.r, sin(t + a) * c1.r);
  Point p2 = c1.p + Point(cos(t - a) * c1.r, sin(t - a) * c1.r);
  return { p1, p2 };
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_F
// 点 p を通る円 c の接線
pair<Point, Point> tangent(const Circle &c1, const Point &p2) {
  return crosspoint(c1, Circle(p2, sqrt(norm(c1.p - p2) - c1.r * c1.r)));
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_G
// 円 c1, c2 の共通接線
Lines tangent(Circle c1, Circle c2) {
  Lines ret;
  if (c1.r < c2.r)
    swap(c1, c2);
  Real g = norm(c1.p - c2.p);
  if (eq(g, 0))
    return ret;
  Point u = (c2.p - c1.p) / sqrt(g);
  Point v = rotate(PI * 0.5, u);
  for (int s: { -1, 1 }) {
    Real h = (c1.r + s * c2.r) / sqrt(g);
    if (eq(1 - h * h, 0)) {
      ret.emplace_back(c1.p + u * c1.r, c1.p + (u + v) * c1.r);
    } else if (1 - h * h > 0) {
      Point uu = u * h, vv = v * sqrt(1 - h * h);
      ret.emplace_back(c1.p + (uu + vv) * c1.r, c2.p - (uu + vv) * c2.r * s);
      ret.emplace_back(c1.p + (uu - vv) * c1.r, c2.p - (uu - vv) * c2.r * s);
    }
  }
  return ret;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_B
// 凸性判定
bool is_convex(const Polygon &p) {
  int n = (int)p.size();
  for (int i = 0; i < n; i++) {
    if (ccw(p[(i + n - 1) % n], p[i], p[(i + 1) % n]) == -1)
      return false;
  }
  return true;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_A
// 凸包
Polygon convex_hull(Polygon &p) {
  int n = (int)p.size(), k = 0;
  if (n <= 2)
    return p;
  sort(p.begin(), p.end());
  vector<Point> ch(2 * n);
  for (int i = 0; i < n; ch[k++] = p[i++]) {
    while (k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS)
      --k;
  }
  for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
    while (k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS)
      --k;
  }
  ch.resize(k - 1);
  return ch;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_C
// 多角形と点の包含判定
enum { OUT, ON, IN };

int contains(const Polygon &Q, const Point &p) {
  bool in = false;
  for (int i = 0; i < Q.size(); i++) {
    Point a = Q[i] - p, b = Q[(i + 1) % Q.size()] - p;
    if (a.imag() > b.imag())
      swap(a, b);
    if (a.imag() <= 0 && 0 < b.imag() && cross(a, b) < 0)
      in = !in;
    if (cross(a, b) == 0 && dot(a, b) <= 0)
      return ON;
  }
  return in ? IN : OUT;
}


// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1033
// 線分の重複除去
void merge_segments(vector<Segment> &segs) {
  auto merge_if_able = [](Segment &s1, const Segment &s2) {
    if (abs(cross(s1.b - s1.a, s2.b - s2.a)) > EPS)
      return false;
    if (ccw(s1.a, s2.a, s1.b) == 1 || ccw(s1.a, s2.a, s1.b) == -1)
      return false;
    if (ccw(s1.a, s1.b, s2.a) == -2 || ccw(s2.a, s2.b, s1.a) == -2)
      return false;
    s1 = Segment(min(s1.a, s2.a), max(s1.b, s2.b));
    return true;
  };

  for (int i = 0; i < segs.size(); i++) {
    if (segs[i].b < segs[i].a)
      swap(segs[i].a, segs[i].b);
  }
  for (int i = 0; i < segs.size(); i++) {
    for (int j = i + 1; j < segs.size(); j++) {
      if (merge_if_able(segs[i], segs[j])) {
        segs[j--] = segs.back(), segs.pop_back();
      }
    }
  }
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1033
// 線分アレンジメント
// 任意の2線分の交点を頂点としたグラフを構築する
vector<vector<int>> segment_arrangement(vector<Segment> &segs, vector<Point> &ps) {
  vector<vector<int>> g;
  int N = (int)segs.size();
  for (int i = 0; i < N; i++) {
    ps.emplace_back(segs[i].a);
    ps.emplace_back(segs[i].b);
    for (int j = i + 1; j < N; j++) {
      const Point p1 = segs[i].b - segs[i].a;
      const Point p2 = segs[j].b - segs[j].a;
      if (cross(p1, p2) == 0)
        continue;
      if (intersect(segs[i], segs[j])) {
        ps.emplace_back(crosspoint(segs[i], segs[j]));
      }
    }
  }
  sort(begin(ps), end(ps));
  ps.erase(unique(begin(ps), end(ps)), end(ps));

  int M = (int)ps.size();
  g.resize(M);
  for (int i = 0; i < N; i++) {
    vector<int> vec;
    for (int j = 0; j < M; j++) {
      if (intersect(segs[i], ps[j])) {
        vec.emplace_back(j);
      }
    }
    for (int j = 1; j < vec.size(); j++) {
      g[vec[j - 1]].push_back(vec[j]);
      g[vec[j]].push_back(vec[j - 1]);
    }
  }
  return (g);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_C
// 凸多角形の切断
// 直線 l.a-l.b で切断しその左側にできる凸多角形を返す
Polygon convex_cut(const Polygon &U, Line l) {
  Polygon ret;
  for (int i = 0; i < U.size(); i++) {
    Point now = U[i], nxt = U[(i + 1) % U.size()];
    if (ccw(l.a, l.b, now) != -1)
      ret.push_back(now);
    if (ccw(l.a, l.b, now) * ccw(l.a, l.b, nxt) < 0) {
      ret.push_back(crosspoint(Line(now, nxt), l));
    }
  }
  return (ret);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_A
// 多角形の面積
Real area(const Polygon &p) {
  Real A = 0;
  for (int i = 0; i < p.size(); ++i) {
    A += cross(p[i], p[(i + 1) % p.size()]);
  }
  return A * 0.5;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_H
// 円と多角形の共通部分の面積
Real area(const Polygon &p, const Circle &c) {
  if (p.size() < 3)
    return 0.0;
  function<Real(Circle, Point, Point)> cross_area = [&](const Circle &c, const Point &a, const Point &b) {
    Point va = c.p - a, vb = c.p - b;
    Real f = cross(va, vb), ret = 0.0;
    if (eq(f, 0.0))
      return ret;
    if (max(abs(va), abs(vb)) < c.r + EPS)
      return f;
    if (distance(Segment(a, b), c.p) > c.r - EPS)
      return c.r * c.r * arg(vb * conj(va));
    auto u = crosspoint(c, Segment(a, b));
    vector<Point> tot{ a, u.first, u.second, b };
    for (int i = 0; i + 1 < tot.size(); i++) {
      ret += cross_area(c, tot[i], tot[i + 1]);
    }
    return ret;
  };
  Real A = 0;
  for (int i = 0; i < p.size(); i++) {
    A += cross_area(c, p[i], p[(i + 1) % p.size()]);
  }
  return A;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_B
// 凸多角形の直径(最遠頂点対間距離)
Real convex_diameter(const Polygon &p) {
  int N = (int)p.size();
  int is = 0, js = 0;
  for (int i = 1; i < N; i++) {
    if (p[i].imag() > p[is].imag())
      is = i;
    if (p[i].imag() < p[js].imag())
      js = i;
  }
  Real maxdis = norm(p[is] - p[js]);

  int maxi, maxj, i, j;
  i = maxi = is;
  j = maxj = js;
  do {
    if (cross(p[(i + 1) % N] - p[i], p[(j + 1) % N] - p[j]) >= 0) {
      j = (j + 1) % N;
    } else {
      i = (i + 1) % N;
    }
    if (norm(p[i] - p[j]) > maxdis) {
      maxdis = norm(p[i] - p[j]);
      maxi = i;
      maxj = j;
    }
  } while (i != is || j != js);
  return sqrt(maxdis);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_5_A
// 最近点対
Real closest_pair(Points ps) {
  if (ps.size() <= 1)
    throw(0);
  sort(begin(ps), end(ps));

  auto compare_y = [&](const Point &a, const Point &b) {
    return imag(a) < imag(b);
  };
  vector<Point> beet(ps.size());
  const Real INF = 1e18;

  function<Real(int, int)> rec = [&](int left, int right) {
    if (right - left <= 1)
      return INF;
    int mid = (left + right) >> 1;
    auto x = real(ps[mid]);
    auto ret = min(rec(left, mid), rec(mid, right));
    inplace_merge(begin(ps) + left, begin(ps) + mid, begin(ps) + right, compare_y);
    int ptr = 0;
    for (int i = left; i < right; i++) {
      if (abs(real(ps[i]) - x) >= ret)
        continue;
      for (int j = 0; j < ptr; j++) {
        auto luz = ps[i] - beet[ptr - j - 1];
        if (imag(luz) >= ret)
          break;
        ret = min(ret, abs(luz));
      }
      beet[ptr++] = ps[i];
    }
    return ret;
  };
  return rec(0, (int)ps.size());
}


int main() {
  int n, m;
  cin >> n >> m;

  vector<Polygon> pols(n);
  rep(i, n) {
    int l;
    cin >> l;

    Points ps(l);
    for (auto &p: ps) {
      cin >> p;
    }

    pols[i] = ps;
  }

  Points ps(m);
  for (auto &p: ps) {
    cin >> p;
  }

  vector<Segments> pol_segs(n);
  rep(i, n) {
    rep(j, len(pols[i]) - 1) {
      pol_segs[i].emplace_back(pols[i][j], pols[i][j + 1]);
    }
  }

  int ans = 0;

  constexpr int lim = 2000;
  for (int x = -lim; x <= lim; x++) {
    for (int y = -lim; y <= lim; y++) {
      Point me = Point(x / 100.0, y / 100.0);

      Segments segs;
      segs.reserve(ps.size());

      for (const auto &p: ps) {
        segs.emplace_back(me, p);
      }

      int sum = 0;

      for (const auto &s1: segs) {
        bool is_intersect = false;
        rep(i, pol_segs.size()) {
          for (const auto &s2: pol_segs[i]) {
            if (intersect(s1, s2)) {
              is_intersect = true;
              goto EXIT;
            }
          }
        }

      EXIT:
        if (not is_intersect) {
          sum++;
        }
      }

      if (chmax(ans, sum)) {
        // debug(x, y, ans);
      }
    }
  }

  cout << ans << newl;
}
accuracy: 0.06521739130434782
time_ms: 1630
memory_kb: 3520
final_rank: 19

code_snippet: namespace luz {

  template < typename T1, typename T2 >
  inline bool chmax(T1 &a, T2 b) {
    return a < b and (a = b, true);
  }

  template < typename T1, typename T2 >
  inline bool chmin(T1 &a, T2 b) {
    return a > b and (a = b, true);
  }

} // namespace luz

#include <iostream>

namespace luz {

  void set_fast_ios() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
  }

} // namespace luz

#include <cstddef>
#include <cstdint>

namespace luz {

  using isize = std::ptrdiff_t;
  using usize = std::size_t;

  using i32 = std::int32_t;
  using i64 = std::int64_t;
  using u32 = std::uint32_t;
  using u64 = std::uint64_t;

} // namespace luz

namespace luz {

  template < typename T = i64 >
  T input() {
    T tmp;
    std::cin >> tmp;
    return tmp;
  }

} // namespace luz

#include <iomanip>

namespace luz {

  void io_set(usize precision) {
    std::cout << std::fixed << std::setprecision(precision);
    std::cerr << std::fixed << std::setprecision(precision);
  }

} // namespace luz

#include <vector>

namespace luz {

  template < typename T >
  std::vector< T > make_vector(usize a, T b) {
    return std::vector< T >(a, b);
  }

  template < typename... Ts >
  auto make_vector(usize a, Ts... ts) {
    return std::vector< decltype(make_vector(ts...)) >(
        a, make_vector(ts...));
  }

} // namespace luz

#include <utility>

namespace luz {

  template < typename T1, typename T2 >
  std::ostream &operator<<(std::ostream &os, std::pair< T1, T2 > p) {
    os << "(" << p.first << ", " << p.second << ")";
    return os;
  }

  template < typename T1, typename T2 >
  std::istream &operator>>(std::istream &is, std::pair< T1, T2 > &p) {
    is >> p.first >> p.second;
    return is;
  }

} // namespace luz

#include <algorithm>

namespace luz {

  struct rep {
    struct itr {
      usize i;
      constexpr itr(const usize i) noexcept: i(i) {}
      void operator++() noexcept {
        ++i;
      }
      constexpr usize operator*() const noexcept {
        return i;
      }
      constexpr bool operator!=(const itr x) const noexcept {
        return i != x.i;
      }
    };
    const itr f, l;
    constexpr rep(const usize f, const usize l) noexcept
        : f(std::min(f, l)),
          l(l) {}
    constexpr auto begin() const noexcept {
      return f;
    }
    constexpr auto end() const noexcept {
      return l;
    }
  };

  struct rrep {
    struct itr {
      usize i;
      constexpr itr(const usize i) noexcept: i(i) {}
      void operator++() noexcept {
        --i;
      }
      constexpr usize operator*() const noexcept {
        return i;
      }
      constexpr bool operator!=(const itr x) const noexcept {
        return i != x.i;
      }
    };
    const itr f, l;
    constexpr rrep(const usize f, const usize l) noexcept
        : f(l - 1),
          l(std::min(f, l) - 1) {}
    constexpr auto begin() const noexcept {
      return f;
    }
    constexpr auto end() const noexcept {
      return l;
    }
  };

} // namespace luz

namespace luz {

  template < typename T >
  std::ostream &operator<<(std::ostream &os,
                           const std::vector< T > vs) {
    for (usize i: rep(0, vs.size())) {
      os << vs[i] << (i + 1 != vs.size() ? " " : "");
    }
    return os;
  }

  template < typename T >
  std::istream &operator>>(std::istream &is, std::vector< T > &vs) {
    for (T &v: vs) {
      is >> v;
    }
    return is;
  }

} // namespace luz

#include <complex>
#include <cmath>
#include <istream>
#include <ostream>

// base
namespace geometry {
  using namespace std;
  using real_number = long double;

  const real_number PI = acosl(-1);

  inline static real_number &eps() {
    static real_number EPS = 1e-10;
    return EPS;
  }

  static void set_eps(real_number EPS) {
    eps() = EPS;
  }

  inline int sign(real_number r) {
    set_eps(1e-10);
    if (r < -eps()) return -1;
    if (r > +eps()) return +1;
    return 0;
  }

  inline bool equals(real_number r1, real_number r2) {
    return sign(r1 - r2) == 0;
  }
}

// point
namespace geometry {
  using point = complex< real_number >;
  using points = vector< point >;

  istream &operator>>(istream &is, point &p) {
    real_number x, y;
    is >> x >> y;
    p = point(x, y);
    return is;
  }

  ostream &operator<<(ostream &os, const point &p) {
    return os << p.real() << " " << p.imag();
  }

  point operator*(const point &p, const real_number &k) {
    return point(p.real() * k, p.imag() * k);
  }

  point rotate(const real_number &theta, const point &p) {
    return point(cos(theta) * p.real() + sin(-theta) * p.imag(),
                 sin(theta) * p.real() + cos(-theta) * p.imag());
  }

  bool equals(const point &a, const point &b) {
    return equals(a.real(), b.real()) and equals(a.imag(), b.imag());
  }
}

using geometry::operator>>;
using geometry::operator<<;

// polygon
namespace geometry {
  using polygon = vector< point >;
  using polygons = vector< polygon >;
}

// line 
namespace geometry {
  struct line {
    point a, b;

    line() = default;
    line(point a, point b) : a(a), b(b) {}
  };

  using lines = vector< line >;
}

// segment
namespace geometry {
  struct segment : line {
    segment() = default;
    using line::line;
  };

  using segments = vector< segment >;
}

// product
namespace geometry {
  real_number cross(const point &a, const point &b) {
    return a.real() * b.imag() - a.imag() * b.real();
  }

  real_number dot(const point &a, const point &b) {
    return a.real() * b.real() + a.imag() * b.imag();
  }
}

// ccw
namespace geometry {
  constexpr int COUNTER_CLOCKWISE = +1;
  constexpr int CLOCKWISE         = -1;
  constexpr int ONLINE_BACK       = +2; // c-a-b
  constexpr int ONLINE_FRONT      = -2; // a-b-c
  constexpr int ON_SEGMENT        =  0; // a-c-b
  int ccw(const point &a, point b, point c) {
    b = b - a, c = c - a;
    if (sign(cross(b, c)) == +1) return COUNTER_CLOCKWISE;
    if (sign(cross(b, c)) == -1) return CLOCKWISE;
    if (sign(dot(b, c)) == -1) return ONLINE_BACK;
    if (norm(b) < norm(c)) return ONLINE_FRONT;
    return ON_SEGMENT;
  }
}

// intersect
namespace geometry {
  bool is_intersect(const segment &s1, const segment &s2) {
    return ccw(s1.a, s1.b, s2.a) * ccw(s1.a, s1.b, s2.b) <= 0 &&
           ccw(s2.a, s2.b, s1.a) * ccw(s2.a, s2.b, s1.b) <= 0;
  }
}

// parallel
namespace geometry {
  bool is_parallel(const line &l1, const line &l2) {
    return equals(cross(l1.b - l1.a, l2.b - l2.a), 0);
  }
}

// cross point
namespace geometry {
  point cross_point_ll(const line &l1, const line &l2) {
    real_number a = cross(l1.b - l1.a, l2.b - l2.a);
    real_number b = cross(l1.b - l1.a, l1.b - l2.a);
    if (equals(a, 0) && equals(b, 0)) return l2.a;
    return l2.a + (l2.b - l2.a) * b / a;
  }
}

using namespace geometry;

namespace luz {

  void main_() {
    usize n = input(), m = input();
    if (m == 1) {
      std::cout << 1 << std::endl;
      return;
    }

    segments segs;
    points vs;

    for (usize _: rep(0, n)) {
      usize l = input();
      polygon poly;

      while (l--) {
        real_number x, y;
        std::cin >> x >> y;
        poly.emplace_back(x, y);
        vs.emplace_back(x, y);
      }

      for (usize i: rep(1, poly.size() + 1)) {
        segs.emplace_back(poly[i - 1], poly[i % poly.size()]);
      }
    }

    points people;
    for (usize _: rep(0, m)) {
      real_number x, y;
      std::cin >> x >> y;
      people.emplace_back(x, y);
    }

    points pts;

    {
      lines ls;
      for (auto &p1: vs) for (auto &p2: people) {
        ls.emplace_back(p1, p2);
      }

      for (usize i: rep(0, ls.size())) for (usize j: rep(0, i)) {
        auto &l1 = ls[i], &l2 = ls[j];
        if (is_parallel(l1, l2)) continue;
        pts.emplace_back(cross_point_ll(l1, l2));
      }
    }

    auto count = [&](point p) {
      usize res = 0;
      for (auto &pt: people) {
        if (equals(pt, p)) {
          res++;
          continue;
        }

        segment s1(p, pt);

        bool f = true;
        usize cnt_v = 0;
        for (auto &s2: segs) {
          if (not is_intersect(s1, s2)) continue;

          auto cs = cross_point_ll(s1, s2);
          if (equals(s1.a, cs) or equals(s1.b, cs)) continue;
          if (equals(s2.a, cs) or equals(s2.b, cs)) continue;

          f = false;
        }
        if (cnt_v == 2) f = false;

        if (f) res++;
      }

      return res;
    };

    usize ans = 0;
    for (auto &p: pts) {
      if (chmax(ans, count(p))) {
        // std::cerr << p << std::endl;
      }
    }

    std::cout << ans << std::endl;
  }

} // namespace luz

int main() {
  luz::set_fast_ios();
  luz::io_set(15);

  luz::main_();
}
accuracy: 1
time_ms: 30
memory_kb: 3836
final_rank: 6

code_snippet: #include <algorithm>
#include <bitset>
#include <cassert>
#include <chrono>
#include <climits>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <memory>
#include <numeric>
#include <optional>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

/* macro */

#define rep(i, a, n) for (int i = (int)(a); i < (int)(n); i++)
#define rrep(i, a, n) for (int i = ((int)(n - 1)); i >= (int)(a); i--)
#define Rep(i, a, n) for (i64 i = (i64)(a); i < (i64)(n); i++)
#define RRep(i, a, n) for (i64 i = ((i64)(n - i64(1))); i >= (i64)(a); i--)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define Bit(n) (1LL << (n))

/* macro end */

/* template */

namespace ebi {

#ifdef LOCAL
#define debug(...)                                                      \
    std::cerr << "LINE: " << __LINE__ << "  [" << #__VA_ARGS__ << "]:", \
        debug_out(__VA_ARGS__)
#else
#define debug(...)
#endif

void debug_out() { std::cerr << std::endl; }

template <typename Head, typename... Tail>
void debug_out(Head h, Tail... t) {
    std::cerr << " " << h;
    if (sizeof...(t) > 0) std::cout << " :";
    debug_out(t...);
}

template <typename T1, typename T2>
std::ostream &operator<<(std::ostream &os, const std::pair<T1, T2> &pa) {
    return os << pa.first << " " << pa.second;
}

template <typename T1, typename T2>
std::istream &operator>>(std::istream &os, std::pair<T1, T2> &pa) {
    return os >> pa.first >> pa.second;
}

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &vec) {
    for (std::size_t i = 0; i < vec.size(); i++)
        os << vec[i] << (i + 1 == vec.size() ? "" : " ");
    return os;
}

template <typename T>
std::istream &operator>>(std::istream &os, std::vector<T> &vec) {
    for (T &e : vec) std::cin >> e;
    return os;
}

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::optional<T> &opt) {
    if (opt) {
        os << opt.value();
    } else {
        os << "invalid value";
    }
    return os;
}

using std::size_t;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;

template <class T, T init>
auto make_vector(int n) {
    return std::vector<T>(n, init);
}

template <class T, T init, typename Head, typename... Tail>
auto make_vector(Head n, Tail... ts) {
    return std::vector(n, make_vector<T, init>(ts...));
}

template <class T>
inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}

template <class T>
inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

template <class T>
T pow(T x, i64 n) {
    T res = 1;
    while (n > 0) {
        if (n & 1) res = res * x;
        x = x * x;
        n >>= 1;
    }
    return res;
}

template <class T>
T mod_pow(T x, i64 n, i64 mod) {
    T res = 1;
    while (n > 0) {
        if (n & 1) res = (res * x) % mod;
        x = (x * x) % mod;
        n >>= 1;
    }
    return res;
}

template <class T>
T scan() {
    T val;
    std::cin >> val;
    return val;
}

template <class T>
struct Edge {
    int to;
    T cost;
    Edge(int _to, T _cost = 1) : to(_to), cost(_cost) {}
};

template <class T>
struct Graph : std::vector<std::vector<Edge<T>>> {
    using std::vector<std::vector<Edge<T>>>::vector;
    void add_edge(int u, int v, T w, bool directed = false) {
        (*this)[u].emplace_back(v, w);
        if (directed) return;
        (*this)[v].emplace_back(u, w);
    }
};

struct graph : std::vector<std::vector<int>> {
    using std::vector<std::vector<int>>::vector;
    void add_edge(int u, int v, bool directed = false) {
        (*this)[u].emplace_back(v);
        if (directed) return;
        (*this)[v].emplace_back(u);
    }
};

constexpr i64 LNF = std::numeric_limits<i64>::max() / 4;

constexpr int INF = std::numeric_limits<int>::max() / 2;

const std::vector<int> dy = {1, 0, -1, 0, 1, 1, -1, -1};
const std::vector<int> dx = {0, 1, 0, -1, 1, -1, 1, -1};

}  // namespace ebi

namespace ebi {

constexpr long double EPS = 1e-7;

const long double PI = std::acos(-1);

namespace internal {

int sgn(long double a) { return (a < -EPS) ? -1 : (a > EPS) ? 1 : 0; }

long double add(long double a, long double b) {
    if (std::abs(a + b) < EPS * (std::abs(a) + std::abs(b))) return 0;
    return a + b;
}

}  // namespace internal

long double arg_to_radian(long double arg) {
    return PI * arg / (long double)(180);
}

struct point {
    long double x, y;

    point() = default;

    point(long double x, long double y) : x(x), y(y) {}

    point &operator+=(const point rhs) noexcept {
        x = internal::add(x, rhs.x);
        y = internal::add(y, rhs.y);
        return *this;
    }

    point &operator-=(const point rhs) noexcept {
        x = internal::add(x, -rhs.x);
        y = internal::add(y, -rhs.y);
        return *this;
    }

    point &operator*=(const point rhs) noexcept {
        long double _x = internal::add(x * rhs.x, -y * rhs.y);
        long double _y = internal::add(x * rhs.y, y * rhs.x);
        x = _x;
        y = _y;
        return *this;
    }

    point &operator*=(const long double k) noexcept {
        x *= k;
        y *= k;
        return *this;
    }

    point &operator/=(const long double k) {
        assert(internal::sgn(k) != 0);
        x /= k;
        y /= k;
        return *this;
    }

    point operator+(const point &rhs) const noexcept {
        return point(*this) += rhs;
    }

    point operator-(const point &rhs) const noexcept {
        return point(*this) -= rhs;
    }

    point operator*(const point &rhs) const noexcept {
        return point(*this) *= rhs;
    }

    point operator*(const long double rhs) const noexcept {
        return point(*this) *= rhs;
    }

    point operator/(const long double rhs) const { return point(*this) /= rhs; }

    point operator-() const noexcept { return point(0, 0) - *this; }

    long double abs() const noexcept {
        return std::sqrt(internal::add(x * x, y * y));
    }

    long double dot(const point rhs) const noexcept {
        return internal::add(x * rhs.x, y * rhs.y);
    }

    long double det(const point rhs) const noexcept {
        return internal::add(x * rhs.y, -y * rhs.x);
    }

    // arctan(y/x) (単位はラジアン)

    long double arg() const { return std::atan2(y, x); }

    // x昇順, その後y昇順

    bool operator<(const point &rhs) const noexcept {
        if (internal::sgn(x - rhs.x)) return internal::sgn(x - rhs.x) < 0;
        return internal::sgn(y - rhs.y) < 0;
    }

    bool operator==(const point &rhs) const noexcept {
        if (internal::sgn(x - rhs.x) == 0 && internal::sgn(y - rhs.y) == 0)
            return true;
        else
            return false;
    }
};

std::ostream &operator<<(std::ostream &os, const point &a) {
    return os << a.x << " " << a.y;
}

std::istream &operator>>(std::istream &os, point &a) {
    return os >> a.x >> a.y;
}

point conj(const point &a) { return point(a.x, -a.y); }

// 点a をang(ラジアン)回転する

point rot(const point &a, long double ang) {
    return point(std::cos(ang) * a.x - std::sin(ang) * a.y,
                 std::sin(ang) * a.x + std::cos(ang) * a.y);
}

point rot90(const point &a) { return point(-a.y, a.x); }

long double dot(const point &a, const point &b) { return a.dot(b); }

long double det(const point &a, const point &b) { return a.det(b); }

long double abs(const point &a) { return a.abs(); }

long double norm(const point &a) { return internal::add(a.x * a.x, a.y * a.y); }

int isp(const point &a, const point &b, const point &c) {
    int flag = internal::sgn(det(b - a, c - a));
    if (flag == 0) {
        if (internal::sgn(dot(b - a, c - a)) < 0) return -2;
        if (internal::sgn(dot(a - b, c - b)) < 0) return +2;
    }
    return flag;
}

// 分割統治で最近点対を求める O(N log N)

long double closest_pair(std::vector<point> p) {
    std::sort(p.begin(), p.end());
    int n = p.size();
    auto f = [&](auto &&self, int l, int r) -> long double {
        if (r - l == 1) {
            return 1e9;
        }
        int mid = (l + r) / 2;
        long double x = p[mid].x;
        long double d = std::min(self(self, l, mid), self(self, mid, r));
        std::vector<point> b;
        b.reserve(r - l);
        int j = mid;
        for (int i = l; i < mid; i++) {
            while (j < r && p[j].y <= p[i].y) {
                b.emplace_back(p[j++]);
            }
            b.emplace_back(p[i]);
        }
        while (j < r) {
            b.emplace_back(p[j++]);
        }
        for (int i = 0; i < r - l; i++) {
            p[l + i] = b[i];
        }
        b.clear();
        for (int i = l; i < r; i++) {
            if (std::abs(p[i].x - x) >= d) continue;
            for (int j = int(b.size()) - 1; j >= 0; j--) {
                if (p[i].y - b[j].y >= d) break;
                d = std::min(d, abs(p[i] - b[j]));
            }
            b.emplace_back(p[i]);
        }
        return d;
    };
    return f(f, 0, n);
}

// ∠ABCを求める(ラジアン)

long double angle(const point &A, const point &B, const point &C) {
    long double a = (B - C).abs(), b = (C - A).abs(), c = (A - B).abs();
    long double cos =
        internal::add(internal::add(a * a, c * c), -b * b) / (2.0 * c * a);
    return std::acos(cos);
}

void arg_sort(std::vector<point> &a) {
    int n = a.size();
    std::vector ps(4, std::vector<point>());
    auto idx = [](point v) -> int {
        if (v.y >= 0)
            return (v.x >= 0) ? 0 : 1;
        else
            return (v.x >= 0) ? 3 : 2;
    };
    for (auto p : a) {
        assert(!(p.x == 0 && p.y == 0));
        ps[idx(p)].emplace_back(p);
    }
    a.clear();
    a.reserve(n);
    for (int i = 0; i < 4; i++) {
        std::sort(ps[i].begin(), ps[i].end(), [](point &p1, point &p2) -> bool {
            int flag = internal::sgn(internal::add(p1.x * p2.y, -p2.x * p1.y));
            return flag == 0 ? (norm(p1) < norm(p2)) : flag > 0;
        });
        for (auto &p : ps[i]) a.emplace_back(p);
    }
    return;
}

template <class T>
void arg_sort_ll(std::vector<std::pair<T, T>> &a) {
    using Point = std::pair<T, T>;
    int n = a.size();
    std::vector ps(4, std::vector<Point>());
    auto idx = [](Point v) -> int {
        if (v.second >= 0)
            return (v.first >= 0) ? 0 : 1;
        else
            return (v.first >= 0) ? 3 : 2;
    };
    for (auto p : a) {
        assert(!(p.first == 0 && p.second == 0));
        ps[idx(p)].emplace_back(p);
    }
    a.clear();
    a.reserve(n);
    for (int i = 0; i < 4; i++) {
        std::sort(ps[i].begin(), ps[i].end(), [](Point &p1, Point &p2) -> bool {
            T flag = p1.first * p2.second - p2.first * p1.second;
            return flag == 0 ? (p1.first * p1.first + p1.second * p1.second <
                                p2.first * p2.first + p2.second * p2.second)
                             : flag > 0;
        });
        for (auto &p : ps[i]) a.emplace_back(p);
    }
    return;
}

}  // namespace ebi

namespace ebi {

struct line {
    point a, b;

    line(long double x1, long double y1, long double x2, long double y2)
        : a(x1, y1), b(x2, y2) {}

    line(const point &a, const point &b) : a(a), b(b) {}

    point proj(const point &p) const {
        return a + (b - a) * (dot(b - a, p - a) / norm(b - a));
    }

    point relf(const point &p) const { return proj(p) * double(2) - p; }

    long double distance(const point &c) const {
        return std::abs(det(c - a, b - a) / abs(b - a));
    }
};

int intersection(const line &a, const line &b) {
    if (internal::sgn(det(a.b - a.a, b.a - b.b)) != 0) {
        if (internal::sgn(dot(a.b - a.a, b.b - b.a)) == 0) {  // 垂直
            return 1;
        }
        return 0;                                                // 交差
    } else if (internal::sgn(det(a.b - a.a, b.a - a.a)) != 0) {  // 平行
        return 2;
    } else {  // 同一直線
        return 3;
    }
}

point cross_point(const point &a, const point &b, const point &c,
                  const point &d) {
    return a + (b - a) * det(c - a, d - c) / det(b - a, d - c);
}

// 交点があるか確認する！
point cross_point(const line &s, const line &t) {
    assert(intersection(s, t) < 2);
    return s.a +
           (s.b - s.a) * det(t.a - s.a, t.b - t.a) / det(s.b - s.a, t.b - t.a);
}

// 直線aと点cの距離
long double distance(const line &a, const point &c) {
    return std::abs(det(c - a.a, a.b - a.a) / abs(a.b - a.a));
}

long double distance(const line &a, const line &b) {
    if (intersection(a, b) < 2) {
        return 0;
    } else {
        return distance(a, b.a);
    }
}

}  // namespace ebi

namespace ebi {

struct line_segment {
    point a, b;

    line_segment() = default;

    line_segment(long double x1, long double y1, long double x2, long double y2)
        : a(x1, y1), b(x2, y2) {}

    line_segment(const point &a, const point &b) : a(a), b(b) {}
};

// 線分ab, cd が交わるか判定
bool intersection_line_segment(const point &a, const point &b, const point &c,
                               const point &d) {
    if (internal::sgn(isp(a, b, c) * isp(a, b, d)) <= 0 &&
        internal::sgn(isp(c, d, a) * isp(c, d, b)) <= 0) {
        return true;
    }
    return false;
}

// 線分ab, cd が交わるか判定
bool intersection(const line_segment &a, const line_segment &b) {
    return intersection_line_segment(a.a, a.b, b.a, b.b);
}

bool intersection(const line &a, const line_segment &b) {
    if (internal::sgn(det(a.b - a.a, b.a - a.a)) *
            internal::sgn(det(a.b - a.a, b.b - a.a)) <
        0) {
        return true;
    } else {
        return false;
    }
}

point cross_point(const line_segment &s, const line_segment &t) {
    assert(intersection(s, t));
    return s.a +
           (s.b - s.a) * det(t.a - s.a, t.b - t.a) / det(s.b - s.a, t.b - t.a);
}

long double distance(const line_segment &a, const point &c) {
    if (internal::sgn(dot(a.b - a.a, c - a.a)) < 0) {
        return abs(c - a.a);
    } else if (internal::sgn(dot(a.a - a.b, c - a.b)) < 0) {
        return abs(c - a.b);
    } else {
        return std::abs(det(c - a.a, a.b - a.a) / abs(a.b - a.a));
    }
}

long double distance(const line_segment &a, const line_segment &b) {
    if (intersection(a, b)) {
        return 0;
    } else {
        return std::min(std::min(distance(a, b.a), distance(a, b.b)),
                        std::min(distance(b, a.a), distance(b, a.b)));
    }
}

long double distance(const line &a, const line_segment &b) {
    if (intersection(a, b)) {
        return 0;
    } else {
        return std::min(distance(a, b.a), distance(a, b.b));
    }
}

}  // namespace ebi

namespace ebi {

void main_() {
    int n, m;
    std::cin >> n >> m;
    std::vector<std::vector<point>> polies(n);
    rep(i, 0, n) {
        int l;
        std::cin >> l;
        polies[i].resize(l);
        std::cin >> polies[i];
    }
    std::vector<point> people(m);
    std::cin >> people;
    std::vector<line> ls;
    for (const auto &poly : polies) {
        for (const auto &p : poly) {
            for (const auto &human : people) {
                ls.emplace_back(p, human);
            }
        }
    }
    auto calc_ang = [&](point a, point b, point c) -> long double {
        long double cos = dot((a-b), (c-b)) / (abs(a-b) * abs(c-b));
        long double sin = det((a-b), (c-b)) / (abs(a-b) * abs(c-b));
        return std::atan2(sin, cos);
    };
    int ans = 0;
    auto check = [&](const std::vector<point> &poly, point p) -> bool {
        long double ret = 0;
        int sz = poly.size();
        rep(i,0,sz) {
            if(internal::sgn(distance(line_segment(poly[i], poly[(i+1)%sz]), p)) == 0) {
                return true;
            }
        }
        rep(i, 0, sz) { ret += calc_ang(poly[i], p, poly[(i + 1) % sz]); }
        if (internal::sgn(ret) == 0) {
            return true;
        }
        return false;
    };
    for (auto l1 : ls) {
        for (auto l2 : ls) {
            if (intersection(l1, l2) >= 2) continue;
            point p = cross_point(l1, l2);
            int ret = 0;
            {
                bool flag = true;
                for (const auto &poly : polies) {
                    if (!check(poly, p)) {
                        flag = false;
                        break;
                    }
                }
                if(!flag) {
                    continue;
                }
            }
            for (const auto &human : people) {
                line_segment l(p, human);
                bool flag = true;
                for (const auto &poly : polies) {
                    if (!flag) break;
                    int sz = poly.size();
                    rep(i, 0, sz) {
                        line_segment lp(poly[i], poly[(i + 1) % sz]);
                        if (intersection(l, lp)) {
                            point cross = cross_point(l, lp);
                            if (cross == poly[i] || cross == poly[(i + 1) % sz] || cross == p)
                                continue;
                            else {
                                flag = false;
                                break;
                            }
                        }
                    }
                }
                if (flag) ret++;
            }
            chmax(ans, ret);
        }
    }
    std::cout << ans << '\n';
}

}  // namespace ebi

int main() {
    std::cout << std::fixed << std::setprecision(15);
    std::cin.tie(nullptr);
    std::ios::sync_with_stdio(false);
    int t = 1;
    // std::cin >> t;
    while (t--) {
        ebi::main_();
    }
    return 0;
}
accuracy: 1
time_ms: 170
memory_kb: 3632
final_rank: 4