1. 程式人生 > >2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror) Solution

2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror) Solution

瞎扯

  又來打比賽了,發現自己菜得不行。

  果然我是標準的普及組選手。(這個隊名是啥意思?我也不知道,因為不知道取啥隊名,就隨機在鍵盤上敲Emmm)

  這次隊友很給力,把我不會的模擬和貪心全切掉了,並且每次翻譯了正確的題意(我英語真垃圾)。(上次UESTC ACM Final的隊友讓我很絕望,既不會做題又給我翻譯假題面)

  然後我把剩下的送分題都切掉了。

  於是被碾壓了:

  開始通讀全題(提供pdf真良心,避免網絡卡耽誤時間),我覺得很絕望,尤其是那個B,讀得我很絕望,直接扔翻譯裡都棄了。

  之後並不知道怎麼做題,然後隨機一道題,發現是水題是一道水題就直接切掉了。

  之後就開始看榜,那個題通過的隊多就做哪個。

  佬表示這個不是正確的做法,正確的做法是每個人隨機若干道題,先自己去做,不會的話然後扔給隊友。

  掛掉的話也可以扔隊友。

  但是我和我隊友都挺菜的,這麼搞可能完蛋了。

  下來發現B,J都是送分題。

Problem A Find a Number

題目大意

  問最小的滿足各位數字之和為$s$並且能被$d$整除的正整數。

  首先用bfs確定它的位數,每個狀態記錄通過儘量小的轉移邊轉移的前驅。

  然後做完了。

Code

 1 /**
 2  * Codeforces
 3  * Problem#1070A
4 * Accepted 5 * Time: 108ms 6 * Memory: 24800k 7 * Author: yyf 8 */ 9 #include <iostream> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cstdio> 13 #include <queue> 14 using namespace std; 15 typedef bool boolean; 16 17 const int N = 5005, D = 505
; 18 #define pii pair<int, int> 19 #define fi first 20 #define sc second 21 22 int d, s; 23 int f[N][D]; 24 char lst[N][D]; 25 int lstr[N][D]; 26 boolean vis[N][D]; 27 28 pii trans(int s, int r, int dig) { 29 return pii(s + dig, (r * 10 + dig) % d); 30 } 31 32 inline void init() { 33 scanf("%d%d", &d, &s); 34 } 35 36 queue<pii> que; 37 boolean bfs() { 38 que.push(pii(0, 0)); 39 memset(f, 0x3f, sizeof(f)); 40 f[0][0] = 0, vis[0][0] = true; 41 while (!que.empty()) { 42 pii e = que.front(); 43 que.pop(); 44 45 for (int i = 0; i <= 9; i++) { 46 pii eu = trans(e.fi, e.sc, i); 47 if (eu.fi > s) 48 break; 49 if (vis[eu.fi][eu.sc]) 50 continue; 51 vis[eu.fi][eu.sc] = true; 52 lst[eu.fi][eu.sc] = i + '0'; 53 lstr[eu.fi][eu.sc] = e.sc; 54 f[eu.fi][eu.sc] = f[e.fi][e.sc] + 1; 55 que.push(eu); 56 } 57 } 58 return vis[s][0]; 59 } 60 61 void print(int s, int r) { 62 if (!s && !r) 63 return ; 64 int nr = lstr[s][r]; 65 print(s - lst[s][r] + '0', nr); 66 putchar(lst[s][r]); 67 } 68 69 70 inline void solve() { 71 if (bfs()) { 72 print(s, 0); 73 } else 74 puts("-1"); 75 } 76 77 int main() { 78 init(); 79 solve(); 80 return 0; 81 }
Problem A

Problem B Berkomnadzor

題目大意

  給定一個IPv4白名單和黑名單,要求用最少的IPv4碼給出一個包含所有黑名單中的地址但不包含任何一個白名單裡的地址。

  先判掉無解的情況。

  剩下直接分治。

Code

  1 /**
  2  * Codeforces
  3  * Problem#1070B
  4  * Accepted
  5  * Time: 530ms
  6  * Memory: 52800k
  7  */
  8 #include <bits/stdc++.h>
  9 using namespace std;
 10 typedef bool boolean;
 11 
 12 #define ull unsigned long long
 13 #define pii pair<int, int>
 14 #define ll long long
 15 #define ui unsigned
 16 #define sc second
 17 #define fi first
 18 
 19 const signed ll llf = (signed ll) (~0ull >> 1);
 20 const signed int inf = (signed) (~0u >> 1);
 21 
 22 template <typename T>
 23 T __abs(T x) {
 24     return (x < 0) ? (-x) : (x);
 25 }
 26 
 27 template <typename T>
 28 void pfill(T* pst, const T* ped, T val) {
 29     for ( ; pst != ped; *(pst++) = val);
 30 }
 31 
 32 template <typename T>
 33 void pcopy(T* pst, const T* ped, T* pv) {
 34     for ( ; pst != ped; *(pst++) = *(pv++));
 35 }
 36 
 37 #define digit(_x) ((_x) >= '0' && (_x) <= '9')
 38 
 39 template <typename T>
 40 char* read(char* s, T& u) {
 41     for ( ; *s && !digit(*s); s++);
 42     if (!*s)
 43         return NULL;
 44     for (u = *s - '0'; ++s, digit(*s); u = u * 10 + *s - '0');
 45     return s;
 46 }
 47 
 48 const int N = 2e5 + 5;
 49 
 50 typedef class Segment {
 51     public:
 52         ui l, r;
 53         ui sgn;
 54 
 55         Segment() {    }
 56         Segment(ui l, ui r, ui sgn):l(l), r(r), sgn(sgn) {    }
 57 
 58         boolean operator < (Segment b) const { 
 59             if (l ^ b.l)
 60                 return l < b.l;
 61             return r < b.r;
 62         }
 63 
 64         boolean intersect(Segment b) {
 65             return !(b.r < l || b.l > r);
 66         }
 67 }Segment;
 68 
 69 int n;
 70 char buf[100];
 71 
 72 Segment read() {
 73     ui l, r, x;
 74     scanf("%s", buf);
 75     ui sgn = (buf[0] == '+');
 76     char* str = buf + 1;
 77     str = read(str, l);
 78     str = read(str, x), l = l << 8 | x;
 79     str = read(str, x), l = l << 8 | x;
 80     str = read(str, x), l = l << 8 | x;
 81     if (*str == '/') {
 82         read(str, x);
 83         x = 32 - x;
 84         l >>= x, l <<= x;
 85         if (x == 32)
 86             r = ~0u;
 87         else
 88             r = l | ((1 << x) - 1);
 89         return Segment(l, r, sgn);
 90     }
 91     return Segment(l, l, sgn);
 92 }
 93 
 94 int res = 0;
 95 vector<Segment> ss, rs;
 96 
 97 inline void init() {
 98     scanf("%d", &n);
 99     Segment s;
100     for (int i = 1; i <= n; i++)
101         s = read(), ss.push_back(s);
102 }
103 
104 void dividing(vector<Segment> &ss, ui l, ui r, ui bit) {
105     if (ss.empty())
106         return;
107     boolean app1 = false, app0 = false;
108     for (ui i = 0; i < ss.size(); i++)
109         app1 |= (ss[i].sgn == 1), app0 |= (ss[i].sgn == 0);
110     
111     if (!app1) {
112         rs.push_back(Segment(l, 32 - bit, 0));
113         return;
114     }
115 
116     if (!app0)
117         return;
118 
119     assert(l ^ r);
120 
121     ui mid = l + ((r - l) >> 1);
122     vector<Segment> ql, qr;
123     for (ui i = 0; i < ss.size(); i++) {
124         if (ss[i].r <= mid)
125             ql.push_back(ss[i]);
126         else if (ss[i].l > mid)
127             qr.push_back(ss[i]);
128         else {
129             ql.push_back(Segment(ss[i].l, mid, ss[i].sgn));
130             qr.push_back(Segment(mid + 1, ss[i].r, ss[i].sgn));
131         }
132     }
133     ss.clear();
134     dividing(ql, l, mid, bit - 1);
135     dividing(qr, mid + 1, r, bit - 1);
136 }
137 
138 inline void solve() {
139     sort(ss.begin(), ss.end());
140     for (ui i = 0, j; i < ss.size(); i = j)
141         for (j = i + 1; j < ss.size() && ss[j].intersect(ss[i]); j++)
142             if (ss[j].sgn ^ ss[i].sgn) {
143                 puts("-1");
144                 return;
145             }
146     dividing(ss, 0, ~0u, 32);
147     printf("%u\n", rs.size());
148     ui msk = (1 << 8) - 1;
149     for (ui i = 0, x; i < rs.size(); i++) {
150         x = rs[i].l;
151         printf("%u.%u.%u.%u/%u\n", x >> 24, x >> 16 & msk, x >> 8 & msk, x & msk, rs[i].r);
152     }
153 }
154 
155 int main() {
156     init();
157     solve();
158     return 0;
159 }
Problem B

Problem C Cloud Computing

題目大意

  一個公司每天需要$K$個CPU核心,有$m$個供應商,在第$l_i$到第$r_i$天,以每個CPU核心$p_i$的價格提供$c_i$個,如果一天買不夠,那麼必須把能夠提供的核心都購買。問最小的總花費。

  隨便拿個資料結構就過了。

Code

  1 /**
  2  * Codeforces
  3  * Problem#1070C
  4  * Accepted
  5  * Time: 249ms
  6  * Memory: 28000k
  7  * Author: yyf
  8  */
  9 #include <algorithm>
 10 #include <iostream>
 11 #include <cstring>
 12 #include <cstdlib>
 13 #include <cstdio>
 14 #include <vector>
 15 using namespace std;
 16 typedef bool boolean;
 17 
 18 typedef class Opt {
 19     public:
 20         int i, p, c;
 21         int sgn;
 22 
 23         Opt(int i, int p, int c, int sgn):i(i), p(p), c(c), sgn(sgn) {    }
 24     
 25         boolean operator < (Opt b) const {
 26             return i < b.i;
 27         }
 28 }Opt;
 29 
 30 const int bzmax = 21;
 31 
 32 template <typename T>
 33 class IndexedTree {
 34     public:
 35         int s;
 36         T* ar;
 37 
 38         IndexedTree() {    }
 39         IndexedTree(int s):s(s) {
 40             ar = new T[(s + 1)];
 41             memset(ar, 0, sizeof(T) * (s + 1));
 42         }
 43 
 44         void add(int idx, T val) {
 45             for ( ; idx <= s; idx += (idx & (-idx)))
 46                 ar[idx] += val;
 47         }
 48 
 49         T query(int idx) {
 50             T rt = 0;
 51             for ( ; idx; idx -= (idx & (-idx)))
 52                 rt += ar[idx];
 53             return rt;
 54         }
 55 
 56         int kth(int k) {
 57             int rt = 0, cur = 0;
 58             for (int l = (1 << (bzmax - 1)); l; l >>= 1)
 59                 if ((rt | l) <= s && (cur + ar[rt | l]) < k)
 60                     rt |= l, cur += ar[rt];
 61             return rt + 1;
 62         }
 63 };
 64 
 65 #define ll long long
 66 
 67 const int V = 1e6 + 3;
 68 
 69 int n, K, m;
 70 IndexedTree<ll> itc;
 71 IndexedTree<ll> its;
 72 vector<Opt> vs;
 73 
 74 inline void init() {
 75     scanf("%d%d%d", &n, &K, &m);
 76     itc = IndexedTree<ll>(V);
 77     its = IndexedTree<ll>(V);
 78     for (int i = 1, l, r, c, p; i <= m; i++) {
 79         scanf("%d%d%d%d", &l, &r, &c, &p);
 80         vs.push_back(Opt(l, p, c, 1));
 81         vs.push_back(Opt(r + 1, p, c, -1));
 82     }
 83 }
 84 
 85 ll res = 0;
 86 inline void solve() {
 87     sort(vs.begin(), vs.end());
 88     int pv = 0, s = (signed) vs.size();
 89     for (int i = 1; i <= n; i++) {
 90         while (pv < s && vs[pv].i == i) {
 91             itc.add(vs[pv].p, vs[pv].c * vs[pv].sgn);
 92             its.add(vs[pv].p, vs[pv].c * 1ll * vs[pv].p * vs[pv].sgn);
 93             pv++;
 94         }
 95         ll cnt = itc.query(V);
 96         if (cnt < K) {
 97             res += its.query(V);
 98         } else {
 99             int p = itc.kth(K);
100             cnt = itc.query(p);
101             res += its.query(p) - (cnt - K) * p;
102         }
103     }
104     cout << res << endl;
105 }
106 
107 int main() {
108     init();
109     solve();
110     return 0;
111 }
Problem C

Problem D Garbage Disposal

題目大意

  每天會產生若干垃圾,每天的垃圾只能當天或者後天處理,第$n + 1$天不能留下垃圾。每次處理垃圾至多能處理$k$個單位,問最少的總處理次數。

  隨便模擬一下就過了。

Code

 1 //Author: dream_maker
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 //----------------------------------------------
 5 //typename
 6 typedef long long ll;
 7 //convenient for
 8 #define fu(a, b, c) for (int a = b; a <= c; ++a)
 9 #define fd(a, b, c) for (int a = b; a >= c; --a)
10 #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
11 //inf of different typename
12 const int INF_of_int = 1e9;
13 const ll INF_of_ll = 1e18;
14 //fast read and write
15 template <typename T>
16 void Read(T &x) {
17   bool w = 1;x = 0;
18   char c = getchar();
19   while (!isdigit(c) && c != '-') c = getchar();
20   if (c == '-') w = 0, c = getchar();
21   while (isdigit(c)) {
22     x = (x<<1) + (x<<3) + c -'0';
23     c = getchar();
24   }
25   if (!w) x = -x;
26 }
27 template <typename T>
28 void Write(T x) {
29   if (x < 0) {
30     putchar('-');
31     x = -x; 
32   }
33   if (x > 9) Write(x / 10);
34   putchar(x % 10 + '0');
35 }
36 //----------------------------------------------
37 const int N = 3e5 + 10;
38 ll a[N], n, k, ans = 0;
39 int main() {
40   Read(n), Read(k);
41   fu(i, 1, n) Read(a[i]);
42   fu(i, 1, n - 1) {
43     if (!a[i]) continue;
44     ll num = a[i] / k;
45     if (a[i] % k) ++num;
46     a[i + 1] = max(0ll, a[i + 1] - (num * k - a[i]));
47     ans += num;
48   }
49   if (a[n]) {
50     ans += a[n] / k;
51     if (a[n] % k) ++ans;
52   }
53   Write(ans);
54   return 0;
55 }
Problem D

Problem E Getting Deals Done

題目大意

  有$n$個任務和引數$m$,每個任務有一個耗時$p_i$,以及時限$t$,要求出$d$使得按照下面方式完成的任務儘量多。

  1. 按順序完成$p_i \leqslant d$的任務
  2. 每做$m$個任務需要休息與做這$m$個任務花費的時間相等的時間。

  yangkai覺得這玩意兒可以三分,於是我們成功得到了-5.

  發現有用的$d$一定時某個$p_i$,可以把$p_i$排序,按順序插進樹狀陣列。

  每次可以二分一下求出能夠完成的任務的數量。

  時間複雜度$O(n\log^{2} n)$。

  但是這個可以二分答案。

  判斷條件是是否能夠把所有可做的任務做完。

  答案只可能是它或者它加上1後的情況,

  因為再大的時候不會花更少的時間去做數量相同的任務。

  然後我的垃圾做法就被暴打了。

  然後注意幾個地方:

  1. $p$相同的任務要一起加入樹狀陣列
  2. 樹狀陣列求第$k$大特判$k = 0$。

Code

  1 /**
  2  * Codeforces
  3  * Problem#1070E
  4  * Accepted
  5  * Time: 608ms
  6  * Memory: 4700k
  7  */
  8 #include <algorithm>
  9 #include <iostream>
 10 #include <cstring>
 11 #include <cstdlib>
 12 #include <cstdio>
 13 #ifndef WIN32
 14 #define Auto "%lld"
 15 #else
 16 #define Auto "%I64d"
 17 #endif
 18 using namespace std;
 19 typedef bool boolean;
 20 #define ll long long
 21 
 22 template <typename T>
 23 class IndexedTree {
 24     public:
 25         int s;
 26         T* ar;
 27         
 28         IndexedTree() {    }
 29         IndexedTree(int s):s(s) {
 30             ar = new T[(s + 1)];
 31             memset(ar, 0, sizeof(T) * (s + 1));
 32         }
 33 
 34         void add(int idx, T val) {
 35             for ( ; idx <= s; idx += (idx & (-idx)))
 36                 ar[idx] += val;
 37         }
 38 
 39         T query(int idx) {
 40             T rt = 0;
 41             for ( ; idx; idx -= (idx & (-idx)))
 42                 rt += ar[idx];
 43             return rt;
 44         }
 45 
 46         int kth(int k) {
 47             if (!k)
 48                 return 0;
 49             int rt = 0, cur = 0;
 50             for (int i = (1 << 18); i; i >>= 1)
 51                 if ((rt | i) <= s && ar[rt | i] + cur < k)
 52                     rt |= i, cur += ar[