Rikka with Illuminations Gym - 102012M
Rikka with Illuminations Gym - 102012M
题目大意
给定一个凸多边形。以及\(k\)个灯,问能否选出一些灯,可以使得这些灯的照明范围包括凸多边形所有边。
如上图,\(H\)灯只能照到\(GA\)和\(AB\)两条边。
我们考虑用最少的量表示一个灯照到的所有边。
我们可以发现,照到的边都是相连的,这也就意味着我们可以通过起点和终点表示这些边。
首先,我们考虑环的话,需要扩展一个\(n\),即\([l+n,r+n]\)。这样才能将所有情况都包含进去。
例如我们规定方向是逆时针表示。对于\(H\)灯,\(GA\)和\(AB\)这两条边,就可以表示为线段\([G,B]\)。考虑到\(G<B\),我们就将\(B=B+7=I\),于是线段\([G,B]\)等价于\([G,I]\)。
下面,我们考虑如何找到所有的边。
我们观察这个图,可以发现,\(X1\)和\(X2\)将所有的边都包含了进去。对于\(X1\),其线段表示为\([A,C]\),对于\(X2\),其线段则表示为\([C,A]\),\(A<C\),所以表示为\([C,A+3]=[C,D]\)
两者的线段相连,得到的是\([A,D]\)。
也就是说,当起点\(S\)和终点\(T\),当\(S+n\leq T\)时,我们就可以保证选择的灯包含了所有边。
类似的答案,也包括\([A,D/E/F]\),\([B,E/F],[C,F]\)。
如下图,就是\([A,F]\)
所以我们的代码就分成了两部分
- 第一部分是找到所有灯照亮的边表示的线段
- 第二部分是线段覆盖,能否使得\(S+n\leq T\)
- 两者的复杂度都是\(O(n^2)\)
代码实现:
/**
爆ぜろリアル!弾けろシナプス!パニッシュメント・ディス・ワールド!
';!!!:`
.;%%%%$$$$%%%;.
.;$%;. :%;.
`||` :!.
.!: ::
:; .`.
'` ..
`` .
.. ..
..
`;||!:';|%$$$%%%$$%|;'.
'|%%%%%%%%%%%%%%%%%%%%%%%%%%%%|:.
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$|:
.:!%%%%%%%%%%|!|%%%%$$&$$$%%%%%%%%%%%%%%%%|' `:'.
'!|%%%%%||%%%%%%%%%%%$&&&$%%%%%$$$%%%%%%%%%%%|'':':'.
`|%%%%%%%%%%%%%$%%%%%%%$&&&&$$%%%$$$%%%%%%%%%%%%|;:::'::':`
:%%%%%%$$%%%$$%%$%%%%%%%$&&&&&$$%%|%$%%%|!|%%%%%$!'::::;|!:'.
.;$%%%%%$$%%%$$%%$%%%%%%%%$&&&&&$$$%%$$$%%%!!%$%%%%!::!%%%%|;'.
.;%$%%%$$$%%%$$%%||%$$%%%%$$&&&&&&$$%%$$%%%%%%%$&&&$%$$$$%%%%|:.
;%%%%%$$$%%$&$%%!:!$$$%%%%$&$||&&&&$$%$$$%%%%%%$$$%%%%$$$$%%%|'
:%%$%%$$$$%$&&$%!`'|$&$%%%%$&|`.!&&&&$%$$$%%%%%%%$%%%%%%$$$$%%%;
`!%|%%%$&$%%$&$$|'.'|&&$%%%%$%|!'.:$&&&$$$$%%%%%%%%%%%%%%$$$$%%%|`
;%':%%$&&$%$&|!|'.`:|&&$%%%$$|'''``'%&&&$$$%%%%%%%%%%%%%%$&&$%%%%:
`;' ;%%$&$%%$%;;: .:!%$%%%$|` .. .!&&&$$$%%$%%%$%$$%$$%$&$%%%$;
'' .!%$&&$$%$;`:' `!%%%%:.... ....:$&$$$%$$%%$$$$$%$$%$&$%%%%;
.. .;%$&&&$%|:. ...;%|'..........'|$%%%$$%%$$&&$%$$%%%$%%%$;
;$$&&&$%!` .`....'`.... ......`!%%%$$%%$&&&$$&&$!!$%%%$:
'%$&&&&$!`. .`........``.......`!%%$$$%$&&&&$$&&$;;$%%%%'
'|$&&&&!``..```. ........`|@@|'....`:|%%$$%%$&&&&$$&&$':$%%%|`
`|$&&&&$' .``````'''::`..........``.:%%$&$%|'`!&&$$&&%':%%%%;.
;$$&&|;!:`........... .':`....`````!%$&&$%|;';&&&%|%%';%%%%:
'%$&$: ...................`''`...`:%%$&$$!`..!&&&$;`:;|%%%!`
;$&&%:..................... .':``!%$&&$;...:$&%'`;' ;%%%%:
.;$&&&$:..........`'............`!%$&&&;..'%&&! `!%%%:
.':|&&&|''`.............. ...'|$&&$||$&&&|` :|'``
.!%: `|$%|!:'`.........`:!%$&&&&&$;''. `.
.:!%$%||||||%%$$$$$$$$$%$%%$$$%%:.
`!%$%%%%%%%|||||||||||%|||||||%%%%%$%%%%|:
'%%%%%%%%%%%%||||||||!!|||||||||||%$$%%%%%%%%$%:
:%$$$%%%$%$$%||||||||!;%%||||||||%%%%%%%%%%%%%%%%|'
.;$%%%%$$$$$%%|||||%$$$$$%||||||||%$$%%%%%%%%%%%%%%'
.!%%%%%%$$%%$%%|||||;;%||||||||%$$&&|!%$$%%%$$$$$%;.
.!%%%%%%%%%%%%%%$%||%%%%%%%%%%%$&$$;`;%%%%%%%%$$!.
:%%%%%%%%%%%%%%||%%%%%%%%%%%$$$%%%%%%%%%%%%%|'
:%%%%%%%%%%$$%%%%%%%%%%%%%%%;`;%%%%%%%|:
.;%%%%%%%%%%%%%%%%%%%%%%%%%%%:..:|%%%!.
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|;:`
;$%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%'
`|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$;
.:!%$%%%%%%%%%%%%%%%%%%%%%%%%%%%%$!.
;!';%%%%%%%%%%%%%%%%%%%%%!:`. `|$%'
.;%%%%%%%%%%%||%%%%%%%%%|:';|%$%%%%%;.
.!%%%%%%%%%%%%$$%%%%%%%%%%%%%%%%%%%%%'
.!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$;.
.;%%%%%%%%%%%%$%%%%%%%%%%%%%%%%%%%%%%%'
;%$$%%%%%%%%$$$$%%%%%%%%%%%%%%%%%%%%%'
`|$&$%%%%%%$%$$$%%%%%%%%%%%%$%%%%%$&%%!`
:%$&$%%||%%%%$$%%%$%%%%%$$!:|%||%%$&$%%!`
**/
#if __cplusplus >= 201103L
#pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
#else
#include <algortmphm>
#include <btmpset>
#include <cmath>
#include <iostream>
#include <map>
#include <string.h>
#include <vector>
#endif
using namespace std;
#define inf __INT_MAX__
#define enf INT_MIN
#define INF LLONG_MAX
#define ENF LLONG_MIN
const int MAXN = 1e5 + 10;
const double pi = acos(-1.0);
const double eps = 1e-7;
typedef long long ll;
typedef unsigned long long ull;
#define zhengfu(x) ((x > eps) - (x < -eps))
#define Dprint(...) printf("%.10f\n", ##__VA_ARGS__)
#define Iprint(...) printf("%d\n", ##__VA_ARGS__)
typedef struct point vec;
struct point { //整数点的基本数据结构
ll x, y;
point(ll _x = 0, ll _y = 0)
: x(_x), y(_y) {
}
double len() //模长
{
return sqrt(1.0 * x * x + y * y);
}
vec chuizhi() {
return vec(-y, x);
}
ll operator*(const point &i_T) const //点积
{
return x * i_T.x + y * i_T.y;
}
ll operator^(const point &i_T) const //叉积
{
return x * i_T.y - y * i_T.x;
}
point operator*(int u) const {
return point(x * u, y * u);
}
bool operator==(const point &i_T) const {
return x == i_T.x && y == i_T.y;
}
point operator/(int u) const {
return point(x / u, y / u);
}
point operator+(const point &i_T) {
return point(x + i_T.x, y + i_T.y);
}
point operator-(const point &i_T) {
return point(x - i_T.x, y - i_T.y);
}
friend bool operator<(point a, point b) {
return a.y == b.y ? a.x < b.x : a.y < b.y;
}
friend ostream &operator<<(ostream &out, point &a) {
printf("%lld %lld", a.x, a.y);
return out;
}
friend istream &operator>>(istream &in, point &a) {
scanf("%lld%lld", &a.x, &a.y);
return in;
}
} p[MAXN], pm[MAXN];
struct node {
ll l, r, rk;
};
int main() {
int t;
cin >> t;
while (t--) {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> p[i];
for (int i = 1; i <= m; i++)
cin >> pm[i];
vector<node> v(m + 1);
p[n + 1] = p[1];
for (int i = 1; i <= m; i++) {
ll last = (p[1] - pm[i]) ^ (p[n] - pm[i]);
v[i].rk = i;
for (int j = 1; j <= n; j++) {
ll now = (p[j + 1] - pm[i]) ^ (p[j] - pm[i]);
if (last < 0 && now > 0)
v[i].l = j;
if (last > 0 && now < 0)
v[i].r = j;
last = now;
}
if (v[i].r < v[i].l)
v[i].r += n;
v.push_back(node{v[i].l + n, v[i].r + n, v[i].rk});
}
sort(v.begin() + 1, v.end(), [](node x, node y) { return x.l < y.l; });
int len = v.size() - 1;
vector<int> ans(m + 1);
for (int i = 1; i <= m; i++) {
vector<int> rk;
rk.push_back(v[i].rk); //选取起点
ll nowr = v[i].r; //当前区间最右侧
int pos = i + 1;
bool f = 1; //无答案
node tmp = node{0, -1, 0};
while (nowr < v[i].l + n) { //当区间右侧与左侧+n重合时退出
while (pos <= len && v[pos].l <= nowr) { //对于有重合区域的区间,求取最右端
if (v[pos].r > tmp.r)
tmp = v[pos];
pos++;
}
if (pos >= len || nowr >= tmp.r) { //如果求取区间到达len+1,仍没有重合 或者 包含
f = 0;
break;
}
nowr = tmp.r;
rk.push_back(tmp.rk);
}
if (f && rk.size() < ans.size())
ans = rk;
}
if (ans.size() == m + 1)
cout << -1 << endl;
else {
cout << ans.size() << endl;
for (int i = 0; i < ans.size() - 1; i++)
cout << ans[i] << ' ';
cout << *ans.rbegin() << endl;
}
}
}