Rikka with Illuminations Gym - 102012M

Rikka with Illuminations Gym - 102012M

题目大意

​ 给定一个凸多边形。以及\(k\)个灯,问能否选出一些灯,可以使得这些灯的照明范围包括凸多边形所有边。

yFsNjA.png

​ 如上图,\(H\)灯只能照到\(GA\)\(AB\)两条边。

​ 我们考虑用最少的量表示一个灯照到的所有边。

​ 我们可以发现,照到的边都是相连的,这也就意味着我们可以通过起点和终点表示这些边。

​ 首先,我们考虑环的话,需要扩展一个\(n\),即\([l+n,r+n]\)。这样才能将所有情况都包含进去。

​ 例如我们规定方向是逆时针表示。对于\(H\)灯,\(GA\)\(AB\)这两条边,就可以表示为线段\([G,B]\)。考虑到\(G<B\),我们就将\(B=B+7=I\),于是线段\([G,B]\)等价于\([G,I]\)

​ 下面,我们考虑如何找到所有的边。

yFyUGF.png

​ 我们观察这个图,可以发现,\(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]\)

yF6ndx.png

​ 所以我们的代码就分成了两部分

  • 第一部分是找到所有灯照亮的边表示的线段
  • 第二部分是线段覆盖,能否使得\(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;
        }
    }
}
posted @ 2021-01-30 12:03  CrossAutomaton  阅读(108)  评论(0编辑  收藏  举报