2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror) Partial Solution
Posted yyf0309
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror) Partial Solution相关的知识,希望对你有一定的参考价值。
从这里开始
- 题目列表
- 瞎扯
- Problem A Find a Number
- Problem B Berkomnadzor
- Problem C Cloud Computing
- Problem D Garbage Disposal
- Problem E Getting Deals Done
- Problem F Debate
- Problem G Monsters and Potions
- Problem H BerOS File Suggestion
- Problem I Privatization of Roads in Berland
- Problem J Streets and Avenues in Berhattan
- Problem K Video Posts
- Problem L Odd Federalization
- Problem M Algoland and Berland
瞎扯
又来打比赛了,发现自己菜得不行。
果然我是标准的普及组选手。(这个队名是啥意思?我也不知道,因为不知道取啥队名,就随机在键盘上敲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 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 ", 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 ", 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 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 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 E Getting Deals Done
题目大意
有$n$个任务和参数$m$,每个任务有一个耗时$p_i$,以及时限$t$,要求出$d$使得按照下面方式完成的任务尽量多。
- 按顺序完成$p_i leqslant d$的任务
- 每做$m$个任务需要休息与做这$m$个任务花费的时间相等的时间。
yangkai觉得这玩意儿可以三分,于是我们成功得到了-5.
发现有用的$d$一定时某个$p_i$,可以把$p_i$排序,按顺序插进树状数组。
每次可以二分一下求出能够完成的任务的数量。
时间复杂度$O(nlog^{2} n)$。
但是这个可以二分答案。
判断条件是是否能够把所有可做的任务做完。
答案只可能是它或者它加上1后的情况,
因为再大的时候不会花更少的时间去做数量相同的任务。
然后我的垃圾做法就被暴打了。
然后注意几个地方:
- $p$相同的任务要一起加入树状数组
- 树状数组求第$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[rt]; 53 return rt + 1; 54 } 55 56 void clear() { 57 s = 0; 58 delete[] ar; 59 } 60 }; 61 62 const int N = 2e5 + 5; 63 #define pii pair<int, int> 64 #define fi first 65 #define sc second 66 67 int T; 68 int n, m; 69 ll t; 70 IndexedTree<int> itc; 71 IndexedTree<ll> its; 72 int ps[N]; 73 pii ar[N]; 74 75 inline void init() { 76 scanf("%d%d"Auto, &n, &m, &t); 77 itc = IndexedTree<int>(n); 78 its = IndexedTree<ll>(n); 79 for (int i = 1; i <= n; i++) 80 scanf("%d", ps + i), ar[i] = pii(ps[i], i); 81 } 82 83 int query(int i) { 84 int l = 1, r = i, mid, k, ti; 85 ll s = 0; 86 while (l <= r) { 87 mid = (l + r) >> 1; 88 k = itc.kth(mid); 89 s = its.query(k); 90 ti = (mid - 1) / m * m; 91 k = itc.kth(ti); 92 s += its.query(k); 93 if (s > t) 94 r = mid - 1; 95 else 96 l = mid + 1; 97 } 98 return l - 1; 99 } 100 101 inline void solve() { 102 int ansc = 0, ansd = 1; 103 sort(ar + 1, ar + n + 1); 104 int i = 1, c; 105 while (i <= n) { 106 int cur = ar[i].fi; 107 while (i <= n && ar[i].fi == cur) { 108 itc.add(ar[i].sc, 1); 109 its.add(ar[i].sc, ar[i].fi); 110 i++; 111 } 112 c = query(i - 1); 113 if (c > ansc) 114 ansc = c, ansd = ar[i - 1].fi; 115 } 116 printf("%d %d ", ansc, ansd); 117 } 118 119 void clear() { 120 itc.clear(); 121 its.clear(); 122 } 123 124 int main() { 125 scanf("%d", &T); 126 while (T--) { 127 init(); 128 solve(); 129 clear(); 130 } 131 return 0; 132 }
Problem F Debate
题目大意
有$n$个观众,每个观众有一个观点是否支持$Alice$以及支持$Bob$,和一个影响度。
要求选出一些人使得至少有一半的人支持$Alice$和一半的人支持$Bob$,最大化他们的影响度之和。
两者都支持的一定全选。
然后支持一方的配对选。
剩下的再怎么选都不会改变还能选多少人,直接贪。
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 deque<ll> p[4]; 38 ll n, w, ans = 0; 39 char s[3]; 40 bool cmp(ll a, ll b) { 41 return a > b; 42 } 43 int main() { 44 Read(n); 45 fu(i, 1, n) { 46 scanf("%s", s); 47 Read(w); 48 if (s[0] == ‘0‘) { 49 if (s[1] == ‘0‘) p[0].push_back(w); 50 else p[1].push_back(w); 51 } else { 52 if (s[1] == ‘0‘) p[2].push_back(w); 53 else p[3].push_back(w); 54 } 55 } 56 fu(i, 0, 3) sort(p[i].begin(), p[i].end(), cmp); 57 ll ans = 0, num = 0, cnt0 = 0, cnt1 = 0; 58 fv(i, p[3]) { 59 ans += p[3][i]; 60 num++; 61 cnt0++, cnt1++; 62 } 63 while (p[1].size() && p[2].size()) { 64 num += 2; 65 cnt1++, cnt0++; 66 ans += p[1].front() + p[2].front(); 67 p[1].pop_front(); 68 p[2].pop_front(); 69 } 70 int last = cnt1 * 2 - num; 71 while (last--) { 72 if (!p[0].size() && !p[1].size() && !p[2].size()) break; 73 if (p[0].size()) { 74 bool can = 1; 75 if (p[1].size() && p[1].front() > p[0].front()) can = 0; 76 if (p[2].size() && p[2].front() > p[0].front()) can = 0; 77 if (can) { 78 ans += p[0].front(); 79 p[0].pop_front(); 80 continue; 81 } 82 } 83 if (p[1].size()) { 84 bool can = 1; 85 if (p[0].size() && p[0].front() > p[1].front()) can = 0; 86 if (p[2].size() && p[2].front() > p[1].front()) can = 0; 87 if (can) { 88 ans += p[1].front(); 89 p[1].pop_front(); 90 continue; 91 } 92 } 93 if (p[2].size()) { 94 bool can = 1; 95 if (p[1].size() && p[1].front() > p[2].front()) can = 0; 96 if (p[0].size() && p[0].front() > p[2].front()) can = 0; 97 if (can) { 98 ans += p[2].front(); 99 p[2].pop_front(); 100 continue; 101 } 102 } 103 } 104 /*if (p[1].size()) { 105 while (cnt1 * 2 > num && cnt0 * 2 > num) { 106 if (!p[1].size() && !p[0].size()) break; 107 if (!p[1].size() || !p[0].size()) { 108 if (!p[1].size()) { 109 num++; 110 ans += p[0].front(); 111 p[0].pop_front(); 112 } else { 113 num++, cnt0++; 114 ans += p[1].front(); 115 p[1].pop_front(); 116 } 117 } 118 if (p[0].front() > p[1].front()) { 119 num++; 120 ans += p[0].front(); 121 p[0].pop_front(); 122 } else { 123 num++, cnt0++; 124 ans += p[1].front(); 125 p[1].pop_front(); 126 } 127 } 128 } else if (p[2].size()) { 129 while (cnt1 * 2 > num && cnt0 * 2 > num) { 130 if (!p[2].size() && !p[0].size()) break; 131 if (!p[2].size() || !p[0].size()) { 132 if (!p[2].size()) { 133 num++; 134 ans += p[0].front(); 135 p[0].pop_front(); 136 } else { 137 num++, cnt1++; 138 ans += p[2].front(); 139 p[2].pop_front(); 140 } 141 } 142 if (p[0].front() > p[2].front()) { 143 num++; 144 ans += p[0].front(); 145 p[0].pop_front(); 146 } else { 147 num++, cnt1++; 148 ans += p[2].front(); 149 p[2].pop_front(); 150 } 151 } 152 } 153 while (p[0].size() && cnt1 * 2 > num && cnt0 * 2 > num) { 154 num++; 155 ans += p[0].front(); 156 p[0].pop_front(); 157 }*/ 158 Write(ans); 159 return 0; 160 }
Problem G Monsters and Potions
题目大意
(请耐心读原题)
暴力枚举拉力点,暴力枚举一下动的英雄。(能动就直接移动,不是爆搜)
很好奇为什么只有100多个队过。
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 = 1010; 38 ll n, m; 39 ll s[N], h[N], p[N]; 40 ll now[N], tp[N], tot; 41 bool wk[N]; 42 void init() { 43 fu(i, 1, n) now[i] = p[i]; 44 memset(tp, 0, sizeof(tp)); 45 memset(wk, 0, sizeof(wk)); 46 tot = 0; 47 } 48 bool check_walk(ll fro, ll to, ll vl) { 49 if (fro == to) return 1; 50 if (fro > to) { 51 fd(i, fro, to) { 52 if (now[i] < 0 && vl + now[i] < 0) return 0; 53 vl += now[i]; 54 } 55 return 1; 56 } else { 57 fu(i, fro, to) { 58 if (now[i] < 0 && vl + now[i] < 0) return 0; 59 vl += now[i]; 60 } 61 return 1; 62 } 63 } 64 void get_clean(ll l, ll r) { 65 if (l >= r) { 66 fd(i, l, r) now[i] = 0; 67 } else { 68 fu(i, l, r) now[i] = 0; 69 } 70 } 71 struct Node { 72 int id, dis; 73 } w[N]; 74 bool cmp(Node a, Node b) { 75 return a.dis < b.dis; 76 } 77 bool check(int pos) { 78 init(); 79 fu(i, 1, m) { 80 w[i].id = i; 81 w[i].dis = labs(pos - s[i]); 82 } 83 sort(w + 1, w + m + 1, cmp); 84 fu(i, 1, m) { 85 if (check_walk(s[w[i].id], pos, h[w[i].id])) { 86 tp[++tot] = w[i].id; 87 get_clean(s[w[i].id], pos); 88 wk[w[i].id] = 1; 89 } 90 } 91 fu(i, 1, m) { 92 if (!wk[w[i].id]) { 93 if (!check_walk(s[w[i].id], pos, h[w[i].id])) return 0; 94 tp[++tot] = w[i].id; 95 wk[w[i].id] = 1; 96 } 97 } 98 Write(pos); putchar(‘ ‘); 99 fu(i, 1, m) { 100 Write(tp[i]); 101 putchar(‘ ‘); 102 } 103 return 1; 104 } 105 int main() { 106 Read(n), Read(m); 107 fu(i, 1, m) Read(s[i]), Read(h[i]); 108 fu(i, 1, n) Read(p[i]); 109 fu(i, 1, n) 110 if (check(i)) return 0; 111 printf("-1"); 112 return 0; 113 }
Problem H BerOS File Suggestion
题目大意
给定$n$个字符串,每次询问一个字符串,问有多少个字符串包含它作为子串,然后要求随便输出$n$个串中任意一个满足条件的串。
居然有人写AC自动机。牛逼。
我直接Hash。好像可以直接开一个string映射到xxx的map。
感觉我对STL一无所知。
Code
1 /** 2 * Codeforces 3 * Problem#1070E 4 * Accepted 5 * Time: 234ms 6 * Memory: 15900k 7 * Author: yyf 8 */ 9 #include <iostream> 10 #include <cstdlib> 11 #include <cstdio> 12 #include <map> 13 using namespace std; 14 typedef bool boolean; 15 #define ull unsigned long long 16 17 ull base = 233; 18 19 const int N = 1e4 + 3; 20 21 int n, q; 22 char strs[N][10]; 23 map<ull, int> cnt; 24 map<ull, int> lst; 25 26 inline void init() { 27 scanf("%d", &n); 28 for (int i = 1; i <= n; i++) { 29 scanf("%s", strs[i]); 30 char *s = strs[i]; 31 for (int l = 0; s[l]; l++) { 32 ull ha = 0; 33 for (int r = l; s[r]; r++) { 34 ha = ha * base + s[r]; 35 if (lst[ha] != i) { 36 lst[ha] = i; 37 cnt[ha]++; 38 // cerr << "added" << " " << ha << endl; 39 } 40 } 41 } 42 } 43 } 44 45 char str[10]; 46 inline void solve() { 47 scanf("%d", &q); 48 while (q--) { 49 scanf("%s", str); 50 ull ha = 0; 51 for (int i = 0; str[i]; i++) 52 ha = ha * base + str[i]; 53 int r1 = cnt[ha]; 54 if (r1) 55 printf("%d %s ", r1, strs[lst[ha]]); 56 else 57 puts("0 -"); 58 } 59 } 60 61 int main() { 62 init(); 63 solve(); 64 return 0; 65 }
Problem I Privatization of Roads in Berland
题目大意
给定一个$n$个点$m$条边的无向图,有足够多个公司,将每条边分配给一个公司,满足:
- 一个公司最多拥有两条边
- 每个顶点相邻的边至多被分给$K$个公司。
容易发现,如果一个公司拥有了两条边,那么它存在一个公共顶点会比较优。
考虑如果一个顶点的度数大于$K$,那么我们就要硬点它周边$2(d - k)$条边两两配对。
然后每条边建一个点做匹配就完了。
Code
1 /** 2 * Codeforces 3 * Problem#1070I 4 * Accepted 5 * Time: 31ms 6 * Memory: 200k 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 typedef class Edge { 38 public: 39 int ed, nx, cap, f; 40 41 Edge() { } 42 Edge(int ed, int nx, int cap, int f):ed(ed), nx(nx), cap(cap), f(f) { } 43 }Edge; 44 45 typedef class MapManager { 46 public: 47 int *h; 48 vector<Edge> es; 49 50 MapManager() { } 51 MapManager(int n) { 52 h = new int[(n + 1)]; 53 pfill(h, h + n + 1, -1); 54 } 55 56 void addEdge(int u, int v, int cap, int f) { 57 es.push_back(Edge(v, h[u], cap, f)); 58 h[u] = (signed) es.size() - 1; 59 } 60 61 void addArc(int u, int v, int cap) { 62 addEdge(u, v, cap, 0); 63 addEdge(v, u, cap, cap); 64 } 65 66 Edge& operator [] (int p) { 67 return es[p]; 68 } 69 70 void clear() { 71 delete[] h; 72 es.clear(); 73 } 74 }MapManager; 75 76 const int N = 605; 77 78 int n, m, K; 79 int s = 0, t; 80 int mxcap; 81 int deg[N]; 82 MapManager g; 83 84 inline void init() { 85 scanf("%d%d%d", &n, &m, &K); 86 pfill(deg, deg + n + 1, 0); 87 g = MapManager(n + m + 1); 88 for (int i = 1, u, v; i <= m; i++) { 89 scanf("%d%d", &u, &v); 90 deg[u]++, deg[v]++; 91 g.addArc(0, i, 1); 92 g.addArc(i, u + m, 1); 93 g.addArc(i, v + m, 1); 94 } 95 t = n + m + 1, mxcap = 0; 96 for (int i = 1; i <= n; i++) 97 if (deg[i] > K) 98 g.addArc(i + m, t, (deg[i] - K) << 1), mxcap += deg[i] - K; 99 mxcap <<= 1; 100 } 101 102 int cur[N << 1], _div[N << 1]; 103 104 int dfs(int p, int mf) { 105 if (p == t || !mf) 106 return mf; 107 int f, flow = 0; 108 for (int& i = cur[p], e; ~i; i = g[i].nx) { 109 e = g[i].ed; 110 if (g[i].f < g[i].cap && _div[e] == _div[p] + 1 && (f = dfs(e, min(mf, g[i].cap - g[i].f))) > 0) { 111 g[i].f += f; 112 g[i ^ 1].f -= f; 113 mf -= f; 114 flow += f; 115 if (!mf) 116 break; 117 } 118 } 119 return flow; 120 } 121 122 queue<int> que; 123 boolean bfs() { 124 pfill(_div, _div + t + 1, -1); 125 _div[s] = 0; 126 que.push(s); 127 while (!que.empty()) { 128 int e = que.front(); 129 que.pop(); 130 for (int i = g.h[e], eu; ~i; i = g[i].nx) { 131 eu = g[i].ed; 132 if (g[i].cap == g[i].f) 133 continue; 134 if (~_div[eu]) 135 continue; 136 _div[eu] = _div[e] + 1; 137 que.push(eu); 138 } 139 } 140 return _div[t] != -1; 141 } 142 143 int dinic() { 144 int rt = 0; 145 while (bfs()) { 146 pcopy(cur, cur + t + 1, g.h); 147 rt += dfs(s, inf); 148 } 149 return rt; 150 } 151 152 int lab[N]; 153 vector<int> mat[N]; 154 155 inline void solve() { 156 int flow = dinic(), used = 0; 157 158 if (flow != mxcap) { 159 for (int i = 1; i <= m; i++) 160 printf("0 "); 161 putchar(‘ ‘); 162 return; 163 } 164 165 for (int i = 1; i <= n; i++) 166 mat[i].clear(); 167 168 for (int i = 1; i <= m; i++) 169 for (int j = g.h[i]; ~j; j = g[j].nx) 170 if (g[j].cap == g[j].f && g[j].ed > m) { 171 mat[g[j].ed - m].push_back(i); 172 break; 173 } 174 175 pfill(lab + 1, lab + m + 1, 0); 176 for (int i = 1, a, b; i <= n; i++) 177 while (!mat[i].empty()) { 178 a = mat[i].back(); 179 mat[i].pop_back(); 180 b = mat[i].back(); 181 mat[i].pop_back(); 182 183 lab[a] = lab[b] = ++used; 184 } 185 186 for (int i = 1; i <= m; i++) { 187 if (!lab[i]) 188 lab[i] = ++used; 189 printf("%d ", lab[i]); 190 } 191 putchar(‘ ‘); 192 } 193 194 inline void clear() { 195 g.clear(); 196 } 197 198 int T; 199 int main() { 200 scanf("%d", &T); 201 while (T--) { 202 init(); 203 solve(); 204 clear(); 205 } 206 return 0; 207 }
Problem J Streets and Avenues in Berhattan
题目大意
给定一个长度为$K$的字母串,以及$n, m$,要求在$K$中选出不同位置的$n$个字符和$m$个字符,使得$n$个字符中和$m$字符中相同的对数尽量小。
容易发现算贡献的只有一种字符。
然后枚举它,随便dp一下就过了。
时间复杂度$O(n|Sigma|^2)$
感觉用多项式除法可以去掉一个平方。
Code
1 /** 2 * Codeforces 3 * Problem#1070J 4 * Accepted 5 * Time: 46ms 6 * Memory: 1200k 7 * Author: yyf 8 */ 9 #include <bits/stdc++.h> 10 using namespace std; 11 typedef bool boolean; 12 13 template <typename T> 14 void pfill(T* pst, const T* ped, T val) { 15 for ( ; pst != ped; *(pst++) = val); 16 } 17 18 const int N = 2e5 + 5, Alpha = 27; 19 20 int T; 21 int n, m, K; 22 int cnt[Alpha]; 23 boolean f[N]; 24 int g[N]; 25 char str[N]; 26 27 inline void init() { 28 scanf("%d%d%d", &n, &m, &K); 29 scanf("%s", str); 30 pfill(cnt, cnt + Alpha, 0); 31 for (char *p = str; *p; p++) 32 cnt[*p - ‘A‘]++; 33 } 34 35 inline void solve() { 36 int res = (signed) (~0u >> 1); 37 for (int i = 0, used, diff; i < Alpha && res; i++) { 38 pfill(f, f + K + 1, false); 39 f[0] = true; 40 for (int c = 0, s = 0; c < Alpha; c++) 41 if (cnt[c] && (c ^ i)) { 42 for (int j = s; ~j; j--) 43 f[j + cnt[c]] |= f[j]; 44 s += cnt[c]; 45 } 46 47 for (int j = 0; j <= K; j++) 48 g[j] = (f[j] ? j : K + 1); 49 for (int j = K - 1; ~j; j--) 50 g[j] = min(g[j + 1], g[j]); 51 52 for (int c = 0; c <= cnt[i] && c <= n && res; c++) { 53 used = g[n - c] + c; 54 if (K - used >= m) { 55 diff = K - cnt[i] - g[n - c]; 56 if (diff >= m) 57 res = 0; 58 else 59 res = min(res, (m - diff) * c); 60 } 61 } 62 } 63 printf("%d ", res); 64 } 65 66 int main() { 67 scanf("%d", &T); 68 while (T--) { 69 init(); 70 solve(); 71 } 72 return 0; 73 }
Problem K Video Posts
题目大意
(没听过)
(听说是普及题)
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 = 1e5 + 10; 38 ll n, k, a[N], ans[N]; 39 int main() { 40 Read(n), Read(k); 41 fu(i, 1, n) Read(a[i]), a[i] += a[i - 1]; 42 if (a[n] % k) { 43 printf("No"); 44 return 0; 45 } 46 ll len = a[n] / k, last = 0, tot = 0; 47 fu(i, 1, n) { 48 if (a[i] - a[last] == len) { 49 ans[++tot] = i - last; 50 last = i; 51 } else if(a[i] - a[last] > len) { 52 printf("No"); 53 return 0; 54 } 55 } 56 printf("Yes "); 57 fu(i, 1, k) { 58 Write(ans[i]); 59 putchar(‘ ‘); 60 } 61 return 0; 62 }
Problem L Odd Federalization
题目大意
要求把$n$个点$m$条边分成$r$个部分,使得每一部分每个点的度都是偶数(不看不在同一部分内的边),问最小的$r$和方案。
首先来猜想答案小于等于2.
然后把每个点在哪个集合看成未知数$x_i$。
用异或算一下每个点被割掉的边的奇偶性,然后就可以列方程了。
高斯消元 + bitset就没了。
Code
1 /** 2 * Codeforces 3 * Problem#1070L 4 * Accepted 5 * Time: 93ms 6 * Memory: 500k 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 const int N = 2048; 38 39 int n, m; 40 boolean deg[N]; 41 bitset<N> eq[N]; 42 43 void reverse(bitset<N> &bs, int bit) { 44 if (bs.test(bit)) 45 bs.reset(bit); 46 else 47 bs.set(bit); 48 } 49 50 inline void init() { 51 scanf("%d%d", &n, &m); 52 pfill(deg, deg + n, false); 53 for (int i = 0; i < n; i++) 54 eq[i].reset(); 55 for (int i = 1, u, v; i <= m; i++) { 56 scanf("%d%d", &u, &v); 57 u--, v--; 58 eq[u].set(v); 59 eq[v].set(u); 60 reverse(eq[u], u); 61 reverse(eq[v], v); 62 deg[u] = !deg[u], deg[v] = !deg[v]; 63 } 64 } 65 66 void guass() { 67 for (int i = 0; i < n; i++) { 68 int p = -1; 69 for (int j = i; j < n && p == -1; j++) 70 if (eq[j].test(i)) 71 p = j; 72 if (p == -1) 73 continue; 74 swap(eq[p], eq[i]); 75 swap(deg[p], deg[i]); 76 for (int j = 0; j < n; j++) 77 if ((j ^ i) && eq[j].test(i)) 78 eq[j] ^= eq[i], deg[j] ^= deg[i]; 79 } 80 } 81 82 inline void solve() { 83 guass(); 84 int r = 1; 85 for (int i = 0; i < n && r == 1; i++) 86 if (deg[i]) 87 r = 2; 88 printf("%d ", r); 89 for (int i = 0; i < n; i++) 90 printf("%d ", deg[i] + 1); 91 puts(""); 92 } 93 94 int T; 95 int main() { 96 scanf("%d", &T); 97 while (T--) { 98 init(); 99 solve(); 100 } 101 return 0; 102 }
!-- .mycontent>
以上是关于2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror) Partial Solution的主要内容,如果未能解决你的问题,请参考以下文章
2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror) 体验记
2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred)
2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred)
Codeforces 1089K - King Kog's Reception - [线段树][2018-2019 ICPC, NEERC, Northern Eurasia Finals P
2013-2014 ACM-ICPC, NEERC, Eastern Subregional Contest PART (7/10)