JZOJ 5832. 【省选模拟8.20】Emotional Flutter

 

中二少年cenbo幻想自己有Eternal Feather。他认为自己的走的每一步都是一次Emotional Flutter。

现在cenbo要走过一条斑马线,斑马线是由n条交替的黑条和白条构成的,第一条是黑条。

cenbo脚的长度是s。cenbo要求在走的过程中,他脚的任何一部分都不能碰到象征邪恶的黑条。

第一条之前和第n条之后的部分都是白色的,cenbo可以任意选择第一条之前的位置出发。

但出发位置一旦选定,之后cenbo的每一步的长度都必须是k。

请你判断cenbo有没有可能在不碰到黑条的情况下通过斑马线,即走到第n条之后。

30%的数据,n<=1300;

50%的数据,n<=22000;

100%的数据,2<=n<=500000, 1<=s<k<=10^9, 1<=A_i<=10^9, 1<=t<=10。

一道noip大概D1的略难于T1,但比T2简单的小水题…… 然后我成功的因为某个低级错误导致爆零

看到题后,看了一下$o(n^2)$的部分分,于是很容易的想出一个可以通过该测试点的暴力:如果最终有解,那么一定是存在一种脚后跟踩到一个白块的左侧,或者脚尖踩到一个白块的右侧的情况,于是可以暴力枚举以哪种方式踩在哪个白块上,然后再计算开始位置并$O(n)$的判断是否不会踩到黑块上

由于这个看起来如果要写的话十分令人不想写,于是激发我们去想一波正解

目前的瓶颈在于如果快速判断一种方案是否合法,不妨换个思路:假设当前枚举的脚的位置是$[x,y]$,那么可以踩到的地方可以写做$[x+kt,y+ky]$的形式,其中$t$是整数变量

观察这个式子,发现就是在模$k$意义下的一段区间(也可能是两端),因此将所有的黑块的范围模$k$后所得到的区间都填上$1$,相当于每次查询一段区间里是否存在$1$,这个做法多种多样,可以直接将线段搞出来后排序+合并+二分,也可以离散化后化作区间赋值+区间求和

注意判断$y-x+1 \ge k$的情况,此时在模$k$意义下是$[0,k-1]$ 这就是我爆零的原因 论大样例的重要性

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const int N = 500000 + 10;
  5 
  6 int s, k, n, a[N], tot;
  7 
  8 ll sum[N], mod;
  9 
 10 struct LN {
 11     int l, r;
 12     bool flag;
 13     LN(int l = 0, int r = 0, int flag = 0) : l(l), r(r), flag(flag) {}
 14 } ln[N * 2], tmp[N * 2];
 15 
 16 bool operator < (LN a, LN b) {
 17     if(a.r == b.r) return a.l > b.l;
 18     else return a.r < b.r;
 19 }
 20 
 21 pair<int, int> checkaft(int pos) {
 22     ll l = sum[pos] - s + 1;
 23     ll r = sum[pos];
 24     if(r - l + 1 >= k) l = 0, r = k - 1;
 25     else l = (l % mod + mod) % mod, r = (r % mod + mod) % mod;
 26     return make_pair(l, r);
 27 }
 28 
 29 pair<int, int> checkbef(int pos) {
 30     ll l = sum[pos - 1] + 1;
 31     ll r = sum[pos - 1] + s;
 32     if(r - l + 1 >= k) l = 0, r = k - 1;
 33     else l = (l % mod + mod) % mod, r = (r % mod + mod) % mod;
 34     return make_pair(l, r);
 35 }
 36 
 37 int check(LN que) {
 38     int l = que.l, r = que.r;
 39 //    printf("check: [%d, %d]\n", l, r);
 40     if(ln[tot].r >= r) {
 41         LN *it = lower_bound(ln + 1, ln + 1 + tot, LN(-1, r));
 42         LN p = *it;
 43         if(p.l <= r) return 1;
 44         else if(it != ln + 1) {
 45             p = * (-- it);
 46             if(l <= p.r && p.r <= r) return 1;
 47         }
 48     } else {
 49         LN p = ln[tot];
 50         if(l <= p.r && p.r <= r) return 1;
 51     }
 52     return 0;
 53 }
 54 
 55 int check(pair<int, int> fafa) {
 56     int l = fafa.first, r = fafa.second;
 57 //    printf("main: [%d, %d]\n", l, r);
 58     if(l <= r) {
 59         if(check(LN(l, r))) return 0;
 60     } else {
 61         if(check(LN(0, r)) || check(LN(l, k - 1))) return 0;
 62     }
 63     return 1;
 64 }
 65 
 66 void sol() {
 67     scanf("%d%d%d", &s, &k, &n);
 68     
 69     mod = k;
 70     tot = 0;
 71     
 72     for(int i = 1 ; i <= n ; ++ i) {
 73         scanf("%d", &a[i]);
 74         sum[i] = sum[i - 1] + a[i];
 75         if(i & 1) {
 76             ll l = sum[i - 1] + 1;
 77             ll r = sum[i];
 78             if(r - l + 1 >= k) l = 0, r = k - 1;
 79             else l = (l % mod + mod) % mod, r = (r % mod + mod) % mod; 
 80             if(l <= r) {
 81                 ln[++ tot] = LN(l, r);
 82             } else {
 83                 ln[++ tot] = LN(l, k - 1);
 84                 ln[++ tot] = LN(0, r);
 85             }
 86         }
 87     }
 88     
 89     sort(ln + 1, ln + 1 + tot);
 90     for(int i = tot ; i >= 1 ; ) {
 91         if(ln[i].flag) -- i;
 92         else {
 93             int pos = i;
 94             while(pos - 1 >= 1 && ln[pos - 1].r >= ln[i].l && ln[pos - 1].l >= ln[i].l) {
 95                 ln[pos - 1].flag = 1;
 96                 -- pos;
 97             }
 98             if(pos == i) -- i;
 99             else i = pos;
100         }
101     }
102     
103     int ttt = 0;
104     for(int i = 1 ; i <= tot ; ++ i) {
105         if(ln[i].flag == 0) tmp[++ ttt] = ln[i];
106     }
107     tot = ttt;
108     for(int i = 1 ; i <= tot ; ++ i) ln[i] = tmp[i];
109     
110 //    for(int i = 1 ; i <= tot ; ++ i) {
111 //        printf("[%d, %d]\n", ln[i].l, ln[i].r);
112 //    }
113     
114     for(int i = 2 ; i <= n ; i += 2) {
115         pair<int, int> bef = checkbef(i);
116         pair<int, int> aft = checkaft(i);
117         if(check(bef) || check(aft)) {
118             puts("TAK");
119             return ;
120         }
121     }
122     
123     ll l, r;
124     
125     l = -s + 1, r = 0;
126     if(r - l + 1 >= k) l = 0, r = k - 1;
127     else l = (l % mod + mod) % mod, r = (r % mod + mod) % mod;
128     if(check(make_pair(l, r))) return puts("TAK"), void();
129     
130     l = sum[n] + 1, r = sum[n] + s;
131     if(r - l + 1 >= k) l = 0, r = k - 1;
132     else l = (l % mod + mod) % mod, r = (r % mod + mod) % mod;
133     if(check(make_pair(l, r))) return puts("TAK"), void();
134     
135     puts("NIE");
136 }
137 
138 int main() {
139     freopen("emotional.in", "r", stdin);
140     freopen("emotional.out", "w", stdout);
141     int T; scanf("%d", &T);
142     while(T --) sol();
143 }
JZOJ 5832. 【省选模拟8.20】Emotional Flutter
posted @ 2018-08-21 18:48  KingSann  阅读(367)  评论(0)    收藏  举报