#include using namespace std; using i128 = __int128_t; struct Vec { long long x,y; }; Vec operator+(Vec a,Vec b){ return {a.x+b.x,a.y+b.y}; } Vec operator-(Vec a,Vec b){ return {a.x-b.x,a.y-b.y}; } i128 cross(Vec a,Vec b){ return (i128)a.x*b.y-(i128)a.y*b.x; } i128 dot(Vec a,Vec b){ return (i128)a.x*b.x+(i128)a.y*b.y; } Vec norm_dir(Vec v){ long long g=gcd(llabs(v.x),llabs(v.y)); return {v.x/g,v.y/g}; } int half(Vec v){ return (v.y>0 || (v.y==0 && v.x>0))?0:1; } bool angle_less(Vec a,Vec b){ if(half(a)!=half(b)) return half(a)0; } struct Frac { long long n,d; }; // d>0 Frac make_frac(long long n,long long d){ if(d<0) n=-n,d=-d; long long g=gcd(llabs(n),d); return {n/g,d/g}; } bool operator<(Frac a,Frac b){ return (i128)a.n*b.d<(i128)b.n*a.d; } bool operator==(Frac a,Frac b){ return (i128)a.n*b.d==(i128)b.n*a.d; } Frac midpoint(Frac a,Frac b){ return make_frac( (long long)((i128)a.n*b.d+(i128)b.n*a.d), (long long)((i128)2*a.d*b.d) ); } struct Bits { array w{}; }; void set_bit(Bits& b,int i){ b.w[i>>6]|=1ULL<<(i&63); } bool get_bit(const Bits& b,int i){ return (b.w[i>>6]>>(i&63))&1ULL; } void or_bits(Bits& a,const Bits& b){ for(int i=0;i<5;i++) a.w[i]|=b.w[i]; } struct Solver { int n,m,A,W; vector p,dir; map,int> id; int dij[12][12]{}; int between[12][12]{}; // 有効な anchored state では変位 0 も常に可能。 // Bits は非零方向のみを保持する。 Bits ALL; vector trans; // trans[w*A + source_atom] // 原子: // [0,m) : ちょうど dir[i] の半直線 // [m,2m) : dir[i] から dir[i+1] までの開角領域 // 原点はすべての原子錐に含める。 bool in_atom(int a,i128 x,i128 y) const { if(x==0 && y==0) return true; auto cr=[&](Vec u){ return (i128)u.x*y-(i128)u.y*x; }; auto dt=[&](Vec u){ return (i128)u.x*x+(i128)u.y*y; }; if(a0; } int i=a-m; int j=(i+1)%m; return cr(dir[i])>0 && (i128)x*dir[j].y-(i128)y*dir[j].x>0; } Vec representative(int a) const { if(a0 で w-t*d が C に入るものが存在するか。 bool attainable(int source,Vec w,Vec d) const { Frac root[3]; int nr=0; auto add_root=[&](long long a,long long b){ if(b==0) return; if(b<0) a=-a,b=-b; if(a>0) root[nr++]={a,b}; }; auto add_line=[&](Vec u){ add_root( (long long)cross(u,w), (long long)cross(u,d) ); }; if(source0){ if(d.x!=0) add_root(w.x,d.x); else add_root(w.y,d.y); } for(int i=0;i>n; p.resize(n); for(Vec& q:p) cin>>q.x>>q.y; if(n==1) return 1; set> ds; for(int i=0;i rep(A); for(int a=0;a cur(S),nxt(S); vector ok(S),nok(S); vector free_cur(1< active,nactive; vector factive,nfactive; active.reserve(S); nactive.reserve(S); auto add=[ & ]( vector& d, vector& used, vector& list, int mask, int last, const Bits& val ){ int z=mask*n+last; if(!used[z]){ used[z]=1; list.push_back(z); } or_bits(d[z],val); }; auto add_free=[ & ]( vector& used, vector& list, int mask ){ if(!used[mask]){ used[mask]=1; list.push_back(mask); } }; // 最初の線分が新しく確定被覆する点が 0 個。 add_free(free_cur,factive,0); // 最初の線分が新しく確定被覆する点が 1 個。 for(int i=0;i=2 なら、P_0,P_1,...,P_{N-1} を順に結べば // N-1 本で必ず被覆できる。 for(int cost=1;cost