zoukankan      html  css  js  c++  java
  • AtCoder ABC 155F Perils in Parallel

    题目链接:https://atcoder.jp/contests/abc155/tasks/abc155_f

    题目大意

      有$N$个炸弹排成一列,放置在不同的坐标位置,其中部分激活了,部分没激活,有$M$个操控装置,每个操控装置能同时反转坐标区间$[L, R]$上炸弹的激活状态。问能否把所有炸弹调成未激活状态,没有则输出$-1$,有则输出需要需要操作的装置个数并升序输出装置序号,若答案不唯一,随意输出一个即可。

    分析

      把炸弹先按坐标位置从小到大排个序,然后把每个操控装置能同时反转的坐标区间转化为能同时反转的炸弹数组下标区间(这一步相当重要,数据范围直接降了下来),还是记为$[L, R]$,不过这里含义已经变了哦。
      设排序后的第$i$个炸弹为$bomb[i]$。
      对于操控装置的功能,其实等价于先把区间$[0, L - 1]$上炸弹的激活状态反转,再把区间$[0, R]$上炸弹的激活状态反转。为了统一操作,我们把区间右值往后挪一个,这样作用区间就变成$[L, R)$了。于是,操控装置的功能,就等价于先把区间$[0, L - 1]$上炸弹的激活状态反转,再把区间$[0, R - 1]$上炸弹的激活状态反转。为了对应改动,需要假想第$N + 1$个未激活的炸弹,对应下标为$N$。
      设$D[i](0)$为使用第$i$个操作装置把区间$[0, L_i - 1]$上炸弹的激活状态反转。
      设$D[i](1)$为使用第$i$个操作装置把区间$[0, R_i - 1]$上炸弹的激活状态反转。
      那么,我们我们只需要同时地执行$D[i](0)$和$D[i](1)$操作即可。
      再来看下$bomb[i - 1]$和$bomb[i]$,无非有激活状态相同和激活状态不同两种可能情况。
      然后想一下我们的目的,把所有炸弹搞成未激活。
      所有炸弹未激活等价于两两相邻的炸弹激活状态相同且最后一个炸弹($bomb[N]$)未激活。
      设$state[i] = bomb[i - 1] oplus bomb[i]$。
      于是我们只需要同时地执行$D[i](0)$和$D[i](1)$操作,使得$state[i]$全为$0$即可(不存在全激活的可能,因为$bomb[N]$一定是未激活的)。
      接下来中重头戏,构造图,以炸弹数组下标为顶点,操作区间为边构造DAG,于是问题转化为不重复地选择边,使得$state[i]$全为$0$。
      当我们$D[i](0)$时,$state[L_i]$必然发生改变;当我们$D[i](1)$时,$state[R_i]$必然发生改变。
      反之,当我们想要改变$state[X_i]$时,一定是通过$D[i](0)$或$D[i](1)$来实现。
      也就是说,如果要改变顶点$i$的$state[i]$,则必须选中与此顶点相关的一条边,进而与此边相连的另一个顶点的$state$值也发生改变,不断影响下去直到$state[i]$全为$0$或者无法全为$0$。
      可以用$DFS$来实现这个过程(具体可以见代码),如果最后还有节点的$state$值为$1$的话,就表明无法全部设置成未激活。

    代码如下

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 /*-------------------Define Start-------------------*/
      5 typedef bool BL;                        // 布尔类型
      6 typedef char SB;                        // 有符号1字节,8位
      7 typedef unsigned char UB;                // 无符号1字节,8位
      8 typedef short SW;                        // 有符号短整型,16位
      9 typedef unsigned short UW;                // 无符号短整型,16位
     10 typedef long SDW;                        // 有符号整型,32位
     11 typedef unsigned long UDW;               // 无符号整型,32位
     12 typedef long long SLL;                    // 有符号长整型,64位
     13 typedef unsigned long long ULL;            // 无符号长整型,64位
     14 typedef char CH;                        // 单个字符
     15 typedef float R32;                        // 单精度浮点数
     16 typedef double R64;                        // 双精度浮点数
     17 
     18 #define Rep(i, n) for (register SDW i = 0; i < (n); ++i)
     19 #define For(i, s, t) for (register SDW i = (s); i <= (t); ++i)
     20 #define rFor(i, t, s) for (register SDW i = (t); i >= (s); --i)
     21 #define foreach(i, c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
     22 #define ms0(a) memset(a,0,sizeof(a))
     23 #define msI(a) memset(a,0x7f,sizeof(a))
     24 #define LOWBIT(x) ((x)&(-x))
     25 
     26 #define MP make_pair
     27 #define PB push_back
     28 #define ft first
     29 #define sd second
     30 #define ALL(x) x.begin(),x.end()
     31 
     32 #define pr(x) cout << #x << " = " << x << "  "
     33 #define prln(x) cout << #x << " = " << x << endl
     34 
     35 const ULL mod = 1e9 + 7;                //常用模数(可根据题目需要修改)
     36 const ULL inf = 0x7fffffff;                //用来表示无限大
     37 const ULL infLL = 0x7fffffffffffffffLL;    //用来表示无限大
     38 
     39 // 重载<<操作符,用来打印vector 
     40 template < typename T >
     41 ostream& operator<< (ostream& out, vector< T > vec) {
     42     foreach(i, vec) {
     43         if(i != vec.begin()) {
     44             out << " ";
     45         }
     46         out << *i;
     47     }
     48     return out;
     49 }
     50 /*-------------------Define End-------------------*/
     51 
     52 const UDW maxN = 1e5 + 7;
     53 
     54 struct Bomb{
     55     SDW pos; // 炸弹的坐标 
     56     BL st; // 激活状态 
     57     
     58     Bomb() {}
     59     Bomb(SDW pos, BL st) : pos(pos), st(st) {}
     60     
     61     BL operator< (const Bomb &x) const {
     62         return pos < x.pos;
     63     }
     64 };
     65 
     66 struct Vertex{
     67     vector< SDW > next;
     68 }; 
     69 
     70 struct Edge{
     71     SDW id, from, to;
     72     
     73     Edge(SDW id, SDW from, SDW to) : id(id), from(from), to(to) {}
     74 };
     75 
     76 SDW N, M; 
     77 Bomb bomb[maxN];
     78 vector< Edge > E;
     79 Vertex V[maxN];
     80 BL vis[maxN];
     81 SDW k;
     82 vector< SDW > c;
     83 
     84 void addEdge(Edge x) {
     85     V[x.from].next.PB(E.size());
     86     E.PB(x);
     87 }
     88 
     89 void input(){
     90     cin >> N >> M;
     91     Rep(i, N) {
     92         cin >> bomb[i].pos >> bomb[i].st;
     93     }
     94     sort(bomb, bomb + N); // 把炸弹按坐标排序,设bomb[N]为假想的炸弹 
     95     
     96     Rep(i, M) {
     97         SDW L, R;
     98         cin >> L >> R;
     99         // 把坐标覆盖区域[L, R]转化为炸弹下标覆盖区域[u, v),如此一来顶点有V[0]~V[N]一共N+1个 
    100         SDW u = lower_bound(bomb, bomb + N, Bomb(L, false)) - bomb;     // u为覆盖区域[L, R]中离L最近的炸弹在bomb数组中的位置 
    101         SDW v = upper_bound(bomb, bomb + N, Bomb(R, false)) - bomb;     // v为覆盖区域[L, R]中离R最近的炸弹在bomb数组中的位置的后一个位置 
    102         if(u != v) {
    103             addEdge(Edge(i << 1, u, v));
    104             addEdge(Edge(i << 1 | 1, v, u));
    105         }
    106     }
    107 }
    108 
    109 BL dfs(SDW x) {
    110     vis[x] = true;
    111     
    112     foreach(i, V[x].next) {
    113         Edge e = E[*i];
    114         
    115         // 如果dfs(e.to)为真,则代表边e需要被选一次 
    116         if(!vis[e.to] && dfs(e.to)) {
    117             c.PB((e.id >> 1) + 1);
    118             ++k;
    119             // 当边e被选时,以下两个值会发生变化 
    120             bomb[x].st ^= 1;
    121             bomb[e.to].st ^= 1; // 可以不要这条语句,但是写上,便于理解 
    122         }
    123     }
    124     
    125     return bomb[x].st;
    126 }
    127 
    128 void solve(){
    129     rFor(i, N, 1) {
    130         bomb[i].st ^= bomb[i - 1].st;
    131     } 
    132     
    133     For(i, 0, N) {
    134         if(!vis[i] && dfs(i)) {
    135             k = -1;
    136             break;
    137         }
    138     }
    139 }
    140 
    141 void output(){
    142     cout << k << endl;
    143     if(k != -1) {
    144         sort(ALL(c));
    145         cout << c << endl;
    146     }
    147 }
    148 
    149 int main() {
    150     input();
    151     solve();
    152     output();
    153     return 0;
    154 }
    View Code
  • 相关阅读:
    javamail模拟邮箱功能发送电子邮件-基础实战篇(javamail API电子邮件实例)
    javaScript的函数(Function)对象的声明(@包括函数声明和函数表达式)
    java后台调用HttpURLConnection类模拟浏览器请求(一般用于接口调用)
    java 常用concurrent类
    安装php5.5
    Unix 哲学
    mysql创建用户两次授权
    python知识点 07-11
    Gradle 1.3之前的Publishing artifacts
    mysql编码详解
  • 原文地址:https://www.cnblogs.com/zaq19970105/p/12340031.html
Copyright © 2011-2022 走看看