2018-2019 ACM-ICPC, Asia Seoul Regional Contest
ProblemA Circuits
Solved.
题意:
有$n$个矩形,可以放两条平行与$x$轴的线,求怎么放置两条无线长的平行于$x$轴的线,使得他们与矩形相交个数最多
如果一个矩形同时与两条线相交,只算一次。
思路:
离散化后枚举一根线,另一根线用线段树维护,扫描线思想
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 400010 5 int n; 6 int b[N]; 7 int x[N], y[N]; 8 vector <int> in[N], out[N]; 9 int ans[N]; 10 11 namespace SEG 12 { 13 struct node 14 { 15 int Max, lazy; 16 node () {} 17 node (int Max, int lazy) : Max(Max), lazy(lazy) {} 18 void init() { Max = lazy = 0; } 19 void add(int x) 20 { 21 Max += x; 22 lazy += x; 23 } 24 node operator + (const node &other) const 25 { 26 node res; res.init(); 27 res.Max = max(Max, other.Max); 28 return res; 29 } 30 }a[N << 2]; 31 void build(int id, int l, int r) 32 { 33 a[id].init(); 34 if (l == r) 35 return; 36 int mid = (l + r) >> 1; 37 build(id << 1, l, mid); 38 build(id << 1 | 1, mid + 1, r); 39 } 40 void pushdown(int id) 41 { 42 if (!a[id].lazy) return; 43 a[id << 1].add(a[id].lazy); 44 a[id << 1 | 1].add(a[id].lazy); 45 a[id].lazy = 0; 46 } 47 void update(int id, int l, int r, int ql, int qr, int x) 48 { 49 if (l >= ql && r <= qr) 50 { 51 a[id].add(x); 52 return; 53 } 54 int mid = (l + r) >> 1; 55 pushdown(id); 56 if (ql <= mid) update(id << 1, l, mid, ql, qr, x); 57 if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr, x); 58 a[id] = a[id << 1] + a[id << 1 | 1]; 59 } 60 int query(int id, int l, int r, int pos) 61 { 62 if (l == r) return a[id].Max; 63 int mid = (l + r) >> 1; 64 pushdown(id); 65 if (pos <= mid) return query(id << 1, l, mid, pos); 66 else return query(id << 1 | 1, mid + 1, r, pos); 67 } 68 } 69 70 void Hash() 71 { 72 sort(b + 1, b + 1 + b[0]); 73 b[0] = unique(b + 1, b + 1 + b[0]) - b - 1; 74 for (int i = 1; i <= n; ++i) x[i] = lower_bound(b + 1, b + 1 + b[0], x[i]) - b; 75 for (int i = 1; i <= n; ++i) y[i] = lower_bound(b + 1, b + 1 + b[0], y[i]) - b; 76 } 77 78 int main() 79 { 80 while (scanf("%d", &n) != EOF) 81 { 82 b[0] = 0; 83 for (int i = 1; i < N; ++i) 84 in[i].clear(), out[i].clear(); 85 for (int i = 1, tmp; i <= n; ++i) 86 { 87 scanf("%d%d%d%d", &tmp, y + i, &tmp, x + i); 88 // cout << x[i] << " " << y[i] << endl; 89 b[++b[0]] = x[i]; 90 b[++b[0]] = y[i]; 91 } 92 Hash(); 93 SEG::build(1, 1, b[0]); 94 for (int i = 1; i <= n; ++i) 95 { 96 in[x[i]].push_back(i); 97 out[y[i]].push_back(i); 98 SEG::update(1, 1, b[0], x[i], y[i], 1); 99 } 100 int res = 0; 101 for (int i = 1; i <= b[0]; ++i) 102 ans[i] = SEG::query(1, 1, b[0], i); 103 for (int i = 1; i <= b[0]; ++i) 104 { 105 for (auto it : in[i]) 106 SEG::update(1, 1, b[0], x[it], y[it], -1); 107 res = max(res, ans[i] + SEG::a[1].Max); 108 for (auto it : out[i]) 109 SEG::update(1, 1, b[0], x[it], y[it], 1); 110 } 111 printf("%d\n", res); 112 } 113 return 0; 114 }
Problem D Go Latin
Solved.
按题意模拟。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int t; 5 map <string, string> mp; 6 7 int main() 8 { 9 mp["a"] = "as"; 10 mp["i"] = "ios"; 11 mp["y"] = "ios"; 12 mp["l"] = "les"; 13 mp["n"] = "anes"; 14 mp["ne"] = "anes"; 15 mp["o"] = "os"; 16 mp["r"] = "res"; 17 mp["t"] = "tas"; 18 mp["u"] = "us"; 19 mp["v"] = "ves"; 20 mp["w"] = "was"; 21 ios::sync_with_stdio(false); 22 cin.tie(0); cout.tie(0); 23 cin >> t; 24 string s; 25 while (t--) 26 { 27 cin >> s; 28 int len = s.size(); 29 string tmp = ""; 30 tmp += s[len - 1]; 31 if (mp.find(tmp) != mp.end()) 32 { 33 s.erase(s.begin() + len - 1); 34 s += mp[tmp]; 35 } 36 else 37 { 38 tmp = ""; 39 tmp += s[len - 2]; 40 tmp += s[len - 1]; 41 if (mp.find(tmp) != mp.end()) 42 { 43 s.erase(s.begin() + len - 2, s.end()); 44 s += mp[tmp]; 45 } 46 else 47 s += "us"; 48 } 49 cout << s << "\n"; 50 } 51 return 0; 52 }
ProblemE LED
Upsolved.
题意:求一个分段函数的最小最大值
思路:
注意$v = 0$的时候,其余部分二分,贪心验证
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 300010 6 struct node 7 { 8 ll v, l; 9 void scan() 10 { 11 scanf("%lld%lld", &v, &l); 12 l *= 10ll; 13 } 14 bool operator < (const node &other) const { return v < other.v; } 15 }a[N]; 16 int n; 17 18 bool check(ll x) 19 { 20 int i; 21 ll l1, l2; 22 for (i = 1; i <= n; ++i) 23 { 24 if (a[i].l > x) 25 break; 26 } 27 if (i > n) return true; 28 ll Max = 0, Min = (ll)1e11; 29 for (; i <= n; ++i) 30 { 31 Max = max(Max, a[i].l); 32 Min = min(Min, a[i].l); 33 if (Max - (Max + Min) / 2 > x) 34 break; 35 l1 = (Max + Min) / 2; 36 } 37 if (i > n) return true; 38 Max = 0, Min = (ll)1e11; 39 for (; i <= n; ++i) 40 { 41 Max = max(Max, a[i].l); 42 Min = min(Min, a[i].l); 43 if (Max - (Max + Min) / 2 > x) 44 break; 45 l2 = (Max + Min) / 2; 46 } 47 //cout << x << " " << l1 << " " << l2 << endl; 48 if (i <= n) return false; 49 return l2 >= l1; 50 } 51 52 int main() 53 { 54 while (scanf("%d", &n) != EOF) 55 { 56 for (int i = 1; i <= n; ++i) a[i].scan(); 57 sort(a + 1, a + 1 + n); 58 ll base = 0; 59 int j = 0; 60 for (int i = 1; i <= n; ++i) 61 { 62 if (a[i].v == 0) 63 base = max(base, a[i].l); 64 else 65 a[++j] = a[i]; 66 } 67 n = j; 68 ll l = 0, r = (ll)1e11, res = -1; 69 while (r - l >= 0) 70 { 71 ll mid = (l + r) >> 1; 72 if (check(mid)) 73 { 74 res = mid; 75 r = mid - 1; 76 } 77 else 78 l = mid + 1; 79 } 80 res = max(res, base); 81 ll x = res % 10; 82 res /= 10; 83 printf("%lld.%lld\n", res, x); 84 } 85 return 0; 86 }
ProblemF Parentheses
Upsolved.
题意:给出一个表达式,先判合法性,再判是否有括号冗余或者缺少。
思路:
直接判吧,数据里面有一个空行,不要多组读入。。。
vp的时候以为有(-b)这种东西,实际上没有。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 1000100 5 char s[N]; 6 int id[N], len; 7 8 bool ok() 9 { 10 len = strlen(s + 1); 11 for (int i = 1; i <= len; ++i) 12 { 13 if (isalpha(s[i])) 14 id[i] = 0; 15 else if (s[i] == '+' || 16 s[i] == '-' || 17 s[i] == '*' || 18 s[i] == '/' || 19 s[i] == '%') 20 id[i] = 1; 21 else if (s[i] == '(') 22 id[i] = 2; 23 else 24 id[i] = 3; 25 } 26 if (id[1] == 3 || id[len] == 2) return false; 27 if (id[1] == 1 || id[len] == 1) return false; 28 if (len == 1 && id[1] == 0) 29 return true; 30 for (int i = 2, x, y; i <= len; ++i) 31 { 32 x = id[i - 1], y = id[i]; 33 if (x == 0 && y == 0) 34 return false; 35 if (x == 1 && y == 1) 36 return false; 37 if (x == 1 && y == 3) 38 return false; 39 if (x == 2 && y == 1) 40 return false; 41 if (x == 2 && y == 3) 42 return false; 43 if (x == 3 && y == 2) 44 return false; 45 if (x == 3 && y == 0) 46 return false; 47 if (x == 0 && y == 2) 48 return false; 49 } 50 int cnt = 0; 51 for (int i = 1; i <= len; ++i) 52 { 53 if (id[i] == 2) 54 ++cnt; 55 else if (id[i] == 3) 56 { 57 if (cnt == 0) 58 return false; 59 --cnt; 60 } 61 } 62 return cnt == 0; 63 } 64 65 // 0 alpha 66 // 1 + - * / % 67 // 2 ( 68 // 3 ) 69 70 bool work() 71 { 72 if (len == 1) return true; 73 int cnt = 0, sym = 0; 74 for (int i = 1; i <= len; ++i) 75 sym += (id[i] == 1); 76 stack <int> sta; 77 for (int i = 1; i <= len; ++i) 78 { 79 if (id[i] == 0) 80 continue; 81 else if (id[i] <= 2) 82 sta.push(id[i]); 83 else if (id[i] == 3) 84 { 85 int flag = 0; 86 while (!sta.empty()) 87 { 88 int top = sta.top(); sta.pop(); 89 if (top == 2) 90 break; 91 if (top == 1) 92 ++flag; 93 } 94 if (flag == 1) ++cnt; 95 else 96 return false; 97 } 98 } 99 return cnt == sym - 1; 100 } 101 102 int main() 103 { 104 gets(s + 1); 105 { 106 len = strlen(s + 1); 107 //if (len == 0) continue; 108 int now = 0; 109 for (int i = 1; i <= len; ++i) 110 if (s[i] != ' ') 111 s[++now] = s[i]; 112 s[++now] = 0; 113 // cout << s + 1 << endl; 114 if (!ok()) puts("error"); 115 else 116 puts(work() ? "proper" : "improper"); 117 } 118 return 0; 119 }
ProblemK TV Show Game
Solved.
题意:$k$个灯, $n$个人, 每个人猜三个位置的灯的颜色, 要求构造出使得所有人都猜对两个或两个以上数量的灯的颜色的序列。
思路:枚举每个灯的状态, 2-SAT求解。
(2-SAT 不熟练啊 果然还是需要练一练)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e4 + 10; 6 7 struct node{ 8 int lamp1, lamp2, lamp3; 9 int color1, color2, color3; 10 }arr[maxn]; 11 12 int k, n; 13 int vis[maxn << 1]; 14 vector<int>People[maxn], lamp[maxn];//R 0 B 1 15 int Stack[maxn], top; 16 17 void Init() 18 { 19 for(int i = 1; i < maxn; ++i) People[i].clear(); 20 for(int i = 1; i < maxn; ++i) lamp[i].clear(); 21 } 22 23 bool DFS(int u) 24 { 25 if(vis[u ^ 1]) return false; 26 if(vis[u]) return true; 27 vis[u] = 1; 28 Stack[top++] = u; 29 for(auto it : lamp[u]) 30 { 31 for(auto v : People[it]) if(v != u) 32 { 33 if(!DFS(v ^ 1)) return false; 34 } 35 } 36 return true; 37 } 38 39 bool Twosat(int n) 40 { 41 memset(vis, 0, sizeof vis); 42 for(int i = 2; i <= n; i += 2) 43 { 44 if(vis[i] || vis[i ^ 1]) continue; 45 top = 0; 46 if(!DFS(i)) 47 { 48 while(top) vis[Stack[--top]] = 0; 49 if(!DFS(i ^ 1)) return false; 50 } 51 } 52 return true; 53 } 54 55 int main() 56 { 57 while(~scanf("%d %d", &k, &n)) 58 { 59 Init(); 60 for(int i = 1; i <= n; ++i) 61 { 62 char a, b, c; 63 scanf("%d %c %d %c %d %c", &arr[i].lamp1, &a, &arr[i].lamp2, &b, &arr[i].lamp3, &c); 64 65 arr[i].color1 = (a == 'B'); 66 arr[i].color2 = (b == 'B'); 67 arr[i].color3 = (c == 'B'); 68 69 People[i].push_back(arr[i].lamp1 * 2 + (arr[i].color1 ^ 1)); 70 lamp[arr[i].lamp1 * 2 + (arr[i].color1 ^ 1)].push_back(i); 71 72 People[i].push_back(arr[i].lamp2 * 2 + (arr[i].color2 ^ 1)); 73 lamp[arr[i].lamp2 * 2 + (arr[i].color2 ^ 1)].push_back(i); 74 75 People[i].push_back(arr[i].lamp3 * 2 + (arr[i].color3 ^ 1)); 76 lamp[arr[i].lamp3 * 2 + (arr[i].color3 ^ 1)].push_back(i); 77 } 78 if(Twosat(2 * k)) 79 { 80 for(int i = 1; i <= k; ++i) 81 { 82 if(vis[2 * i]) putchar('R'); 83 else putchar('B'); 84 } 85 putchar('\n'); 86 } 87 else puts("-1"); 88 } 89 return 0; 90 }
ProblemL Working Plan
Solved.
题意:$m$个人, $n$天, 每个人一旦开始工作需要连续工作$w$天, 工作完w天后需要休息$h$天, 每天需要$d_i$个人, 每个人要求工作$W_i$天, 求方案。
思路:贪心, 优先使得剩余工作天数多的人工作。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int maxn = 2e3 + 10; 8 9 struct node{ 10 int id; 11 int st, ed; 12 int workday; 13 node(){} 14 node(int id, int st, int ed, int workday): id(id), st(st), ed(ed), workday(workday){} 15 bool operator < (const node &other) const{ 16 if(st != other.st) return st > other.st; 17 else return workday < other.workday; 18 } 19 }; 20 21 bool cmp(node a, node b) 22 { 23 return a.workday < b.workday; 24 } 25 26 int n, m,w, h; 27 int W[maxn], d[maxn]; 28 priority_queue<node>q; 29 priority_queue<int, vector<int>, greater<int> >Day; 30 vector<int>ans[maxn]; 31 node Stack[maxn]; 32 int top; 33 34 void Init() 35 { 36 while(!q.empty()) q.pop(); 37 while(!Day.empty()) Day.pop(); 38 for(int i = 1; i <= m; ++i) ans[i].clear(); 39 } 40 41 int main() 42 { 43 while(~scanf("%d %d %d %d", &m, &n, &w, &h)) 44 { 45 Init(); 46 for(int i = 1; i <= m; ++i) scanf("%d", W + i); 47 for(int i = 1; i <= n; ++i) scanf("%d", d + i); 48 for(int i = 1; i <= m; ++i) q.push(node(i, 0, 0, W[i])); 49 bool flag = true; 50 int cnt = 0; 51 top = 0; 52 for(int i = 1; i <= n; ++i) 53 { 54 while(!Day.empty()) 55 { 56 if(Day.top() < i) Day.pop(); 57 else break; 58 } 59 int daysize = Day.size(); 60 if(daysize > d[i]) 61 { 62 flag = false; 63 break; 64 } 65 if(daysize == d[i]) continue; 66 while(!q.empty()) 67 { 68 if(q.top().st <= i) 69 { 70 Stack[++top] = q.top(); 71 q.pop(); 72 } 73 else 74 { 75 break; 76 } 77 } 78 sort(Stack + 1, Stack + 1 + top, cmp); 79 while(Day.size() < d[i]) 80 { 81 if(top < 1) 82 { 83 flag = false; 84 break; 85 } 86 node tmp = Stack[top--]; 87 tmp.st = i; 88 ans[tmp.id].push_back(i); 89 tmp.st += w; 90 Day.push(tmp.st - 1); 91 tmp.st += h; 92 tmp.workday -= min(w, n - i + 1); 93 if(tmp.workday) q.push(tmp); 94 else cnt++; 95 } 96 if(Day.size() != d[i]) flag= false; 97 if(flag == false) break; 98 } 99 if(cnt != m) flag = false; 100 if(flag) 101 { 102 puts("1"); 103 for(int i = 1; i <= m; ++i) for(int j = 0, len = ans[i].size(); j < len; ++j) printf("%d%c", ans[i][j], " \n"[j == len - 1]); 104 } 105 else puts("-1"); 106 } 107 return 0; 108 }