1. 程式人生 > >2018.2.12 省選模擬賽

2018.2.12 省選模擬賽

trie def max -i 直觀 signed pad 直線 指定

技術分享圖片

技術分享圖片

題目大意

(題目很簡潔了,不需要大意)

  其實顯而易見地可以發現,當被卡一次後後面的路程都是固定了的。

  可以用類似動態規劃的思想來進行預處理。現在的問題就是怎麽知道在某個位置剛等完紅燈然後出發會在哪個路口再次被卡。

  嘗試畫一畫圖:

技術分享圖片

  其中橫軸表示位置,縱軸表示時間,長方體表示紅燈時段。有用的部分長度只有$r + g$,所以在模意義下弄一下就可以減少很多重復和無用狀態:

技術分享圖片

  但是這樣仍然不好處理上面提到的問題,考慮讓線段橫著走,第一個撞著的長方形就是答案。為了實現這個目標,就每個長方形向下移動一段(移動的距離與它和它距起點的距離有關)

技術分享圖片

  比如可能修改後就成了這樣。然後就可以從後向前區間覆蓋來預處理每個路口剛等完紅燈然後到終點的耗時。

Code

 1 // 2018-2-13 Test
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cmath>
 5 #include <ctime>
 6 #include <map>
 7 #ifndef WIN32
 8 #define Auto "%lld"
 9 #else
10 #define Auto "%I64d"
11 #endif
12 using namespace std;
13 typedef bool boolean;
14 #define ll long long 15 #define iter map<int, int>::iterator 16 17 int n, g, r, s; 18 int q; 19 ll *len; 20 ll *dis; 21 map<int, int> mp; 22 23 inline void init() { 24 scanf("%d%d%d", &n, &g, &r); 25 s = g + r; 26 len = new ll[(n + 2)]; 27 dis = new
ll[(n + 2)]; 28 for (int i = 0; i <= n; i++) 29 scanf(Auto, len + i); 30 } 31 32 inline void cover(int l, int r, int x) { 33 iter il = mp.lower_bound(l), ir = mp.upper_bound(r); 34 int temp = -1; 35 if (ir == mp.end() || ir->first > r + 1) { 36 temp = (--ir)->second; 37 ir++; 38 } 39 mp.erase(il, ir); 40 mp[l] = x; 41 if (~temp) 42 mp[r + 1] = temp; 43 // cerr << l << " " << r << endl; 44 } 45 46 inline void solve() { 47 mp[0] = n + 1; 48 dis[n + 1] = 0; 49 for (int i = 1; i <= n; i++) 50 len[i] += len[i - 1]; 51 iter it; 52 for (int i = n; i; i--) { 53 int r = -len[i - 1] % s, l = r + g; 54 if (r < 0) r += s; 55 if (l < 0) l += s; 56 it = mp.upper_bound(r); 57 int j = (--it)->second; 58 int rest = (r + len[j - 1]) % s; 59 int wait = (j != n + 1 && rest >= g) ? (s - rest) : (0); 60 dis[i] = len[j - 1] - len[i - 1] + wait + dis[j]; 61 r = (r) ? (r - 1) : (s - 1); 62 if (l <= r) 63 cover(l, r, i); 64 else 65 cover(0, r, i), cover(l, s - 1, i); 66 // cerr << dis[i] << endl; 67 } 68 ll t; 69 scanf("%d", &q); 70 while (q--) { 71 scanf(Auto, &t); 72 it = mp.upper_bound(t % s); 73 int j = (--it)->second; 74 int r = (t + len[j - 1]) % s; 75 int wait = (j != n + 1 && r >= g) ? (s - r) : (0); 76 printf(Auto"\n", t + wait + len[j - 1] + dis[j]); 77 } 78 } 79 80 int main() { 81 freopen("brt.in", "r", stdin); 82 freopen("brt.out", "w", stdout); 83 init(); 84 solve(); 85 return 0; 86 }

技術分享圖片

題目大意

  給定$A$數組,每次可以選出$A$數組中沒有選過的一個無序對$(A_{i},A_{j})$,然後得到的分數是$A_{i} xor A_{j}$,問選取$m$次得到的最大的分數和模$10^{9} + 7$

  想罵一句這道題,100%的數據不給$m$的範圍,我一直以為$n, m$同階,沒見過這樣坑題面的。。。

  顯然需要把每個數放入Trie樹中。然後二分一下得到第$m$大的值。

  然後考慮在Trie上搞點小計數來得到前$k$大和指定數的異或值的和。考慮每個節點記錄一下它的子樹中包含的數,每一位上的1的個數。

  然後就可以做了。

  真心懷疑這道題有毒,考試時用空間復雜度O(31(n + m))的算法,然後MLE。考完後改題,死活因為常數問題TLE。。為什麽這道題這麽不友好

Code

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 using namespace std;
  6 typedef bool boolean;
  7 
  8 const int M = 1e9 + 7;
  9 
 10 typedef class TrieNode {
 11     public:
 12         int cnt;
 13         int cnts[32];
 14         TrieNode *ch[2];
 15 
 16         TrieNode()    {    }
 17         TrieNode(int cnt, TrieNode* ch1, TrieNode* ch2):cnt(cnt) {
 18             ch[0] = ch1, ch[1] = ch2;
 19             memset(cnts, 0, sizeof(cnts));
 20         }
 21 }TrieNode;
 22 
 23 #define Limit 1700000
 24 
 25 TrieNode pool[Limit];
 26 TrieNode* top = pool;
 27 
 28 TrieNode* newnode() {
 29     if (top == pool + Limit)
 30         return new TrieNode(0, NULL, NULL);
 31     top->cnt = 0, top->ch[0] = top->ch[1] = NULL;
 32     memset(top->cnts, 0, sizeof(top->cnts));
 33     return top++;
 34 }
 35 
 36 TrieNode* newnode(TrieNode* old) {
 37     TrieNode* rt = newnode();
 38     if (old == NULL)    return rt;
 39     *rt = *old;
 40     return rt;
 41 }
 42 
 43 typedef class Trie {
 44     public:
 45         TrieNode* rt;
 46 
 47         Trie():rt(NULL)    {    }
 48 
 49         TrieNode* modify(TrieNode* p, int x, int temp, int cnt) {
 50             TrieNode* np = newnode(p); 
 51             int d = ((x & temp) ? (1) : (0));
 52             np->cnt += cnt;
 53             if (!temp)    return np;
 54             for (int i = 0, j = 1; i <= 30; i++, j <<= 1)
 55                 np->cnts[i] += ((x & j) ? (1) : (0));
 56             np->ch[d] = modify(np->ch[d], x, temp >> 1, cnt);
 57             return np;
 58         }
 59 
 60         void modify(int x, int cnt) {
 61             rt = modify(rt, x, 1 << 30, cnt);
 62         }
 63 
 64         int rank(int x, int a) {
 65              TrieNode *p = rt;
 66             int ret = 0, temp = 1 << 30;
 67             while (temp && p) {
 68                 int dx = ((x & temp) ? (1) : (0)), da = ((a & temp) ? (1) : (0));
 69                 if (dx == 0)
 70                     ret += ((p->ch[da ^ 1]) ? (p->ch[da ^ 1]->cnt) : (0)), p = p->ch[da];
 71                 else
 72                     p = p->ch[da ^ 1];
 73                 temp >>= 1;
 74             }
 75             return ret;
 76         }
 77 
 78         int ksums(int k, int a) {
 79             TrieNode* p = rt;
 80             int ret = 0, temp = 1 << 30;
 81             while (temp && p) {
 82                 int da = ((a & temp) ? (1) : (0));
 83                 int ls = (p->ch[da ^ 1]) ? (p->ch[da ^ 1]->cnt) : (0);
 84                 if (k >= ls) {
 85                     TrieNode* l = p->ch[da ^ 1];
 86                     if (l)
 87                         for (int i = 0, j = 1, dx; i <= 30; i++, j <<= 1) {
 88                             dx = ((a & j) ? (l->cnt - l->cnts[i]) : (l->cnts[i]));
 89                             ret = (ret + (dx * 1ll * j)) % M;
 90                         }
 91                     k -= ls;
 92                     p = p->ch[da];
 93                 } else
 94                     p = p->ch[da ^ 1];
 95                 temp >>= 1;    
 96             }
 97             return ret;
 98         }
 99 }Trie;
100 
101 int n, m;
102 int* ar;
103 Trie* ts;
104 
105 inline void init() {
106     scanf("%d%d", &n, &m);
107     ar = new int[(n + 1)];
108     ts = new Trie[(n + 1)];
109     for (int i = 1; i <= n; i++)
110         scanf("%d", ar + i);
111 }
112 
113 inline int check(int mid) {
114     long long rt = 0;
115     for (int i = 2; i <= n && rt < m; i++)
116         rt += ts[i].rank(mid, ar[i]);
117     return rt;
118 }
119 
120 int res = 0;
121 inline void solve() {
122     for (int i = 2; i <= n; i++) {
123         ts[i].rt = ts[i - 1].rt;
124         ts[i].modify(ar[i - 1], 1);
125     }
126     
127     int l = 0, r = (signed) (~0u >> 1);
128     while (l <= r) {
129         int mid = l + ((r - l) >> 1);
130         if (check(mid) < m)
131             r = mid - 1;
132         else
133             l = mid + 1;
134     }
135     
136     int sk = 0, k;
137     for (int i = 2; i <= n; i++) {
138         k = ts[i].rank(r + 1, ar[i]);
139         res = (res + ts[i].ksums(k, ar[i])) % M;
140         sk += k;
141     }
142 
143     res = (res + (m - sk) * 1ll * (r + 1)) % M;
144     
145     printf("%d\n", res);
146 }
147 
148 int main() {
149     freopen("xor.in", "r", stdin);
150     freopen("xor.out", "w", stdout);
151     init();
152     solve();
153     return 0;
154 }

技術分享圖片

技術分享圖片

題目大意

  請維護一個數據結構,使得它能支持:

  1. 區間加上$k$
  2. 區間詢問從1開始的前綴和的最大值

  記得去年省選後,自己yy出了這麽一道題,然而並不會做,就跑去問學長,學長告訴我分塊加斜率等等,然而我並沒有懂,覺得這麽"獨流"的題應該沒人考吧。現在覺得臉好疼啊。

  但是我覺得最毒的是,我寫的純暴力在氧氣優化下拿了80分.全班開始都以為我是正解寫掛了。

  考慮區間加上$k$對前綴和的影響,畫個圖比較直觀:

技術分享圖片

  其中一段加的是等差數列,後一段就是普通的區間加法。

  若將每個位置看成一個點,橫坐標為下標,縱坐標為前綴和,那麽對詢問區間維護一個上凸殼,答案就是斜率為0的直線和凸殼的切點。

  對於區間加上一個公差為k的等差數列,相當於任意兩點之間斜率增加$k$。修改後凸殼的點集顯然不會改變。另外標記顯然可加。

  但是難以快速合並兩個凸殼,為了避免合並凸殼,所以采用分塊。

  每個塊維護一個凸殼,斜率標記,區間加法標記。

  考慮修改操作,區間兩端暴力重構塊,中間的打tag,後邊把tag也打上。

  考慮查詢操作,區間兩端暴力找,中間在凸殼上二分(只是註意一下tag的存在),最後把答案一起取個max。

  中間取值的時候不要忘記tag的存在。

  (由於這道題和bzoj 2388除了題目描述不一樣,我就直接貼bzoj 2388的代碼了)

Code

  1 /**
  2  * bzoj
  3  * Problem#2388
  4  * Accepted
  5  * Time: 39696ms
  6  * Memory: 3520k
  7  */ 
  8 #include <bits/stdc++.h>
  9 #ifndef WIN32
 10 #define Auto "%lld"
 11 #else
 12 #define Auto "%I64d"
 13 #endif
 14 using namespace std;
 15 typedef bool boolean;
 16 #define ll long long
 17 
 18 const int cs = 350;
 19 const double eps = 1e-8;
 20 
 21 typedef class Chunk {
 22     public:
 23         int s, ed;
 24         ll lazyk;
 25         ll lazys;
 26         ll ar[cs];
 27         int con[cs];
 28         
 29         Chunk():s(0), ed(-1), lazyk(0), lazys(0) {        }
 30         
 31         double slope(int x1, int x2) {
 32             return (ar[x2] - ar[x1]) * 1.0 / (x2 - x1);
 33         }
 34         
 35         void update() {
 36             if (!lazyk && !lazys)    return;
 37             for (int i = 0; i < s; i++)
 38                 ar[i] += lazyk * (i + 1);
 39             for (int i = 0; i < s; i++)
 40                 ar[i] += lazys;
 41             lazyk = lazys = 0;
 42         }
 43         
 44         void rebuild() {
 45             ed = -1;
 46             for (int i = 0; i < s; i++) {
 47                 while (ed >= 1 && slope(con[ed - 1], con[ed]) + eps < slope(con[ed], i))
 48                     ed--;
 49                 con[++ed] = i;
 50             }
 51         }
 52         
 53         int query() {
 54             int l = 0, r = ed;
 55             while (l <= r) {
 56                 int mid = (l + r) >> 1;
 57                 if (!mid || slope(con[mid - 1], con[mid]) + lazyk > eps)
 58                     l = mid + 1;
 59                 else
 60                     r = mid - 1;
 61             }
 62             return con[l - 1];
 63         }
 64         
 65         ll getRealValue(int p) {
 66             return ar[p] + (p + 1) * lazyk + lazys;
 67         }
 68 }Chunk;
 69 
 70 int n, m;
 71 ll *ar;
 72 Chunk ch[350];
 73 
 74 inline void init() {
 75     scanf("%d", &n);
 76     ar = new ll[(n + 1)];
 77     Chunk* p = ch;
 78     for (int i = 0; i < n; i++)
 79         scanf(Auto, ar + i);
 80     for (int i = 1; i < n; i++)
 81         ar[i] += ar[i - 1];
 82     for (int i = 0; i < n; i++) {
 83         p->ar[p->s++] = ar[i];
 84         if (p->s == cs)
 85             p->rebuild(), p++;
 86     }    
 87 }
 88 
 89 inline void bmodify(Chunk* p, int l, int r, ll k, ll s) {
 90     p->update();
 91     for (int i = 0; i <= r - l; i++)
 92         p->ar[l + i] += s + k * (i + 1);
 93     p->rebuild();
 94 }
 95 
 96 inline ll bquery(Chunk* p, int l, int r) {
 97     p->update();
 98     ll rt = p->ar[l];
 99     for (int i = l + 1; i <= r; i++)
100         if (rt < p->ar[i])
101             rt = p->ar[i];
102     return rt;
103 }
104 
105 inline void solve() {
106     int opt, l, r;
107     ll k, base;
108     scanf("%d", &m);
109     while (m--) {
110         scanf("%d%d%d", &opt, &l, &r);
111         l--, r--;
112         if (!opt) {
113             scanf(Auto, &k);
114             base = 0;
115             for (int i = l, ni; i <= r; i = ni) {
116                 ni = (i / cs + 1) * cs;
117                 Chunk* p = ch + (i / cs);
118                 if ((i % cs) || ni > r)
119                     bmodify(p, i % cs, (ni > r) ? (r % cs) : (cs - 1), k, base);
120                 else
121                     p->lazyk += k, p->lazys += base;
122                 base += (ni - i) * k;
123             }
124             base = k * (r - l + 1);
125             for (int i = r + 1, ni; i < n; i = ni) {
126                 ni = (i / cs + 1) * cs;
127                 Chunk* p = ch + (i / cs);
128                 if ((i % cs) || ni >= n)
129                     bmodify(p, i % cs, (ni >= n) ? ((n - 1) % cs) : (cs - 1), 0, base);
130                 else
131                     p->lazys += base;
132             }
133         } else {
134             ll res = 1ll << 63, cmp;
135             for (int i = l, ni; i <= r; i = ni) {
136                 ni = (i / cs + 1) * cs;
137                 Chunk *p = ch + (i / cs);
138                 if ((i % cs) || ni > r)
139                     cmp = bquery(p, i % cs, (ni > r) ? (r % cs) : (cs - 1));
140                 else
141                     cmp = p->getRealValue(p->query());
142                 if (cmp > res)
143                     res = cmp;
144             }
145             printf(Auto"\n", res);
146         }
147     }
148 }
149 
150 int main() {
151     init();
152     solve();
153     return 0;
154 }

2018.2.12 省選模擬賽