CF1557D Ezzat and Grid

题意:给你个n行1e9列的01矩阵。i行和i+1行是相邻的当且仅当存在一列,这两行这一列的数都是1。问最少删掉多少行,才能使对于每个1<=i<m,i行和i+1行都相邻。m是删掉之后的总行数。输出方案。

解:首先发现,两个行能够相邻,一定是通过某个两者都是1的位置联系起来。

怎么做呢,想了一想想到了连边图论,然后马上发现边数是n²的,那没事了。再进一步,想到了DO。就设f[i]表示选了第i行,前面的全都相邻,要删掉的最少行数。那么转移就是对于这一行每个是1的地方,如果前面某一行这里也是1,那么可以从那一行转移来,转移方程是f[i]=min(f[j]+(i-j-1)),发现这个转移方程可以化成f[i]-i=min(f[j]-j)-1,于是我们考虑维护一个数据结构来转移,存f[i]-i的最小值。如果第i行这里是1,就把数据结构的这里改成f[i]-i,查询的时候查询这一行是1的地方的最小值,再-1就可以了。最终答案就是f[n+1]+n+1

记录方案就是DO经典套路,转移的同时记。可以把来源和最值一起扔到线段树里来存。然后我写的时候修改不是区间取min而是区间覆盖,因为我赛时想的是靠后的转移一定更优。赛后证了一下,是对于k<j这两个可行的转移,一定可以把j到k的中间这些行全都删了,也就是f[j]<=f[k]+(j-k-1),也就是f[j]-j<=f[k]-k-1<f[k]-k,所以越靠后的转移越优。

值域是1e9来着所以要离散化一下。我之前动态开点结果MLE on 1

  1 /**
  2  *  There is no end though there is a start in space. ---Infinity.
  3  *  It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
  4  *  Only the person who was wisdom can read the most foolish one from the history.
  5  *  The fish that lives in the sea doesn't know the world in the land.
  6  *  It also ruins and goes if they have wisdom.
  7  *  It is funnier that man exceeds the speed of light than fish start living in the land.
  8  *  It can be said that this is an final ultimatum from the god to the people who can fight.
  9  *  
 10  *  Steins;Gate
 11 **/
 12 
 13 #include <bits/stdc++.h>
 14 typedef long long LL;
 15 inline char gc() {
 16     return getchar();
 17     static char buf[100000], *p1 = buf, *p2 = buf;
 18     if(p1 == p2) {
 19         p2 = (p1 = buf) + fread(buf, 1, 100000, stdin);
 20     }
 21     return (p1 == p2) ? EOF : *p1++;
 22 }
 23 
 24 template <typename T>
 25 inline void read(T& x) {
 26     x = 0;
 27     char c(gc());
 28     int f(1);
 29     while(c < '0' || c > '9') {
 30         if(c == '-') {
 31             f = -1;
 32         }
 33         c = gc();
 34     }
 35     while(c >= '0' && c <= '9') {
 36         x = x * 10 + c - '0';
 37         c = gc();
 38     }
 39     x *= f;
 40 }
 41 
 42 inline LL read() {
 43     LL x;
 44     read(x);
 45     return x;
 46 }
 47 
 48 const int N = 300010;
 49 
 50 struct Node {
 51     int l, r;
 52 };
 53 struct Data {
 54     int val, id;
 55     Data(int V = 0, int I = 0)
 56         : val(V), id(I) {}
 57 };
 58 std::vector<Node> v[N];
 59 int n, m, tot = 1, X[N * 2], top;
 60 Data f[N];
 61 Data Min[N * 8], tag[N * 8];
 62 Data exmin(Data a, Data b) {
 63     if(!a.id)
 64         return b;
 65     if(!b.id)
 66         return a;
 67     if(a.val < b.val) {
 68         return a;
 69     }
 70     return b;
 71 }
 72 inline void pushdown(int o) {
 73     if(tag[o].id) {
 74         int ls = o << 1, rs = o << 1 | 1;
 75         tag[ls] = Min[ls] = tag[o];
 76 
 77         tag[rs] = Min[rs] = tag[o];
 78 
 79         tag[o] = Data(0, 0);
 80     }
 81 }
 82 inline void pushup(int o) {
 83     Min[o] = exmin(Min[o << 1], Min[o << 1 | 1]);
 84 }
 85 void change(int L, int R, int v, int id, int l, int r, int o) {
 86     if(L <= l && r <= R) {
 87         tag[o] = Min[o] = Data(v, id);
 88         return;
 89     }
 90     pushdown(o);
 91     int mid = (l + r) >> 1;
 92     if(L <= mid) {
 93         change(L, R, v, id, l, mid, o << 1);
 94     }
 95     if(mid < R) {
 96         change(L, R, v, id, mid + 1, r, o << 1 | 1);
 97     }
 98     pushup(o);
 99 }
100 
101 Data getMin(int L, int R, int l, int r, int o) {
102     if(L <= l && r <= R) {
103         return Min[o];
104     }
105     pushdown(o);
106     int mid = (l + r) >> 1;
107     Data ans(-1, 0);
108     if(L <= mid) {
109         ans = getMin(L, R, l, mid, o << 1);
110     }
111     if(mid < R) {
112         ans = exmin(ans, getMin(L, R, mid + 1, r, o << 1 | 1));
113     }
114     return ans;
115 }
116 
117 int main() {
118     // printf("%d\n", (sizeof(ls) + sizeof(rs) + sizeof(tag) + sizeof(Min) + sizeof(v)) / 1048576);
119 
120     read(n);
121     read(m);
122     for(int i = 1, x, l, r; i <= m; i++) {
123         read(x);
124         read(l);
125         read(r);
126         v[x].push_back(Node{l, r});
127         X[++top] = l;
128         X[++top] = r;
129     }
130     std::sort(X + 1, X + top + 1);
131     top = std::unique(X + 1, X + top + 1) - X - 1;
132     for(int i = 1; i <= n; i++) {
133         for(int j = 0; j < v[i].size(); j++) {
134             v[i][j].l = std::lower_bound(X + 1, X + top + 1, v[i][j].l) - X;
135             v[i][j].r = std::lower_bound(X + 1, X + top + 1, v[i][j].r) - X;
136         }
137     }
138     for(int i = 1; i <= n; i++) {
139         for(Node node : v[i]) {
140             int L = node.l, R = node.r;
141             f[i] = exmin(f[i], getMin(L, R, 1, top, 1));
142         }
143         f[i].val--;
144         for(Node node : v[i]) {
145             int L = node.l, R = node.r;
146             change(L, R, f[i].val, i, 1, top, 1);
147         }
148         // printf("f %d = %d from %d \n", i, f[i].val + i, f[i].id);
149     }
150     f[n + 1] = Min[1];
151     f[n + 1].val--;
152     printf("%d\n", f[n + 1].val + n + 1);
153     int p = n + 1;
154     while(p) {
155         int nexP = f[p].id;
156         for(int i = nexP + 1; i < p; i++) {
157             printf("%d ", i);
158         }
159         p = nexP;
160     }
161 
162     return 0;
163 }
AC代码

 

posted @ 2021-08-10 16:23  huyufeifei  阅读(51)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜