ACM-ICPC 2018 南京赛区网络预赛 Solution
A. An Olympian Math Problem
cout << n - 1 << endl;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 6 int t; 7 ll n; 8 9 inline void Run() 10 { 11 scanf("%d", &t); 12 while (t--) 13 { 14 scanf("%lld", &n); 15 printf("%lld\n", n - 1); 16 } 17 } 18 19 int main() 20 { 21 #ifdef LOCAL 22 freopen("Test.in", "r", stdin); 23 #endif 24 25 Run(); 26 27 return 0; 28 }
B. The writing on the wall
题意:给出n * m的矩形,找出有多少个子矩形不包含黑块
思路:枚举每一个当右下角的情况,那么情况总数就是黑块构成的边界里面的格子数量,优先队列优化
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 100010 6 #define M 110 7 8 int t, n, m, k; 9 int G[N][M]; 10 int low[M]; 11 12 struct node 13 { 14 ll h, num; 15 inline node() {} 16 inline node(ll h, ll num) : h(h), num(num) {} 17 inline bool operator < (const node &r) const 18 { 19 return h < r.h; 20 } 21 }; 22 23 priority_queue <node> q; 24 25 int main() 26 { 27 #ifdef LOCAL_JUDGE 28 freopen("Text.txt", "r", stdin); 29 #endif // LOCAL_JUDGE 30 scanf("%d", &t); 31 for (int kase = 1; kase <= t; ++kase) 32 { 33 printf("Case #%d: ", kase); 34 memset(G, 0, sizeof G); 35 memset(low, 0, sizeof low); 36 while (!q.empty()) q.pop(); 37 scanf("%d%d%d", &n, &m, &k); 38 for (int i = 1, x, y; i <= k; ++i) 39 { 40 scanf("%d%d", &x, &y); 41 G[x][y] = 1; 42 } 43 ll ans = 0, sum = 0; 44 for (int i = 1; i <= n; ++i) 45 { 46 for (int j = 1; j <= m; ++j) 47 { 48 //if (i % 1000 == 0) cout << i << endl; 49 if (G[i][j] == 1) 50 { 51 while (!q.empty()) q.pop(); 52 sum = 0; 53 low[j] = i; 54 continue; 55 } 56 if (j == 1) 57 { 58 while (!q.empty()) q.pop(); 59 sum = 0; 60 } 61 ll H = i - low[j]; 62 ll num = 1; 63 while (!q.empty() && q.top().h > H) 64 { 65 num += q.top().num; 66 sum -= q.top().h * q.top().num; 67 q.pop(); 68 } 69 sum += num * H; 70 ans += sum; 71 q.emplace(H, num); 72 } 73 } 74 printf("%lld\n", ans); 75 } 76 return 0; 77 }
C. GDY
按题意模拟即可,注意细节
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int Move[] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 2, }; 5 6 struct DT 7 { 8 int num[15], cnt; 9 int score; 10 inline DT() 11 { 12 score = 0; cnt = 0; 13 memset(num, 0, sizeof num); 14 } 15 inline void Get() 16 { 17 for (int i = 1; i <= 13; ++i) 18 score += num[i] * i; 19 } 20 }arr[250]; 21 22 int t, n, m; 23 queue <int> q; 24 25 inline void work() 26 { 27 int turn = 1, pre = -1, tot = 0, nx; 28 for (int i = 0; i < 13; ++i) if (arr[1].num[Move[i]]) 29 { 30 pre = Move[i]; 31 --arr[1].num[Move[i]]; 32 --arr[1].cnt; 33 break; 34 } 35 while (true) 36 { 37 turn = turn % n + 1; 38 if (tot == n - 1) 39 { 40 for (int i = turn; i <= n; ++i) if (!q.empty()) 41 { 42 ++arr[i].cnt; 43 ++arr[i].num[q.front()]; q.pop(); 44 } 45 for (int i = 1; i < turn; ++i) if (!q.empty()) 46 { 47 ++arr[i].cnt; 48 ++arr[i].num[q.front()]; q.pop(); 49 } 50 for (int i = 0; i < 13; ++i) if (arr[turn].num[Move[i]]) 51 { 52 --arr[turn].num[Move[i]]; 53 if (--arr[turn].cnt == 0) return; 54 pre = Move[i]; tot = 0; 55 break; 56 } 57 } 58 else if (pre == 2) tot++; 59 else 60 { 61 if (pre == 13) nx = 1; 62 else nx = pre + 1; 63 if (arr[turn].num[nx]) 64 { 65 --arr[turn].num[nx]; 66 if (--arr[turn].cnt == 0) return; 67 pre = nx; tot = 0; 68 } 69 else 70 { 71 if (arr[turn].num[2]) 72 { 73 --arr[turn].num[2]; 74 if (--arr[turn].cnt == 0) return; 75 pre = 2; tot = 0; 76 } 77 else tot++; 78 } 79 } 80 } 81 } 82 83 inline void Run() 84 { 85 scanf("%d", &t); 86 for (int kase = 1; kase <= t; ++kase) 87 { 88 while (!q.empty()) q.pop(); 89 printf("Case #%d:\n", kase); 90 scanf("%d%d", &n, &m); 91 for (int i = 1, u; i <= m; ++i) 92 { 93 scanf("%d", &u); 94 q.emplace(u); 95 } 96 for (int i = 1; i <= n; ++i) 97 { 98 arr[i] = DT(); 99 for (int j = 1; j <= 5; ++j) 100 { 101 if (!q.empty()) 102 { 103 arr[i].num[q.front()]++; q.pop(); 104 ++arr[i].cnt; 105 } 106 } 107 } 108 work(); 109 for (int i = 1; i <= n; ++i) 110 { 111 arr[i].Get(); 112 if (arr[i].score == 0) puts("Winner"); 113 else printf("%d\n", arr[i].score); 114 } 115 } 116 } 117 118 int main() 119 { 120 #ifdef LOCAL 121 freopen("Test.in", "r", stdin); 122 #endif 123 124 Run(); 125 return 0; 126 }
D. Jerome's House
留坑。
E. AC Challenge
题意:有n道题目,每次提交得到分数$t * a_i + b_i$ 有一些题目的提交必须要某些题目提交之后才能提交,求最后获得的最大分数
思路:记忆化搜索,二进制标记状态 或者 状压DP
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 ll dp[1 << 20]; 8 9 int n; 10 11 struct node { 12 ll ai, bi; 13 int state; 14 inline node(){} 15 inline node(ll ai, ll bi, int state):ai(ai),bi(bi), state(state){} 16 }arr[30]; 17 18 inline ll DFS(int t, int S) 19 { 20 if (t > n) return 0; 21 if (dp[S] != -1) return dp[S]; 22 ll res = 0; 23 for (int i = 0; i < n; ++i) 24 { 25 int tmp = 1 << i; 26 if ((tmp & S) == 0) 27 { 28 if ((S & arr[i].state) != arr[i].state) continue; 29 res = max(res, t * arr[i].ai + arr[i].bi + DFS(t + 1, (S | tmp))); 30 } 31 } 32 dp[S] = res; 33 return res; 34 } 35 36 inline void RUN() 37 { 38 while (~scanf("%d", &n)) 39 { 40 memset(dp, -1, sizeof dp); 41 for (int i = 0; i < n; ++i) 42 { 43 int m; 44 int S = 0; 45 scanf("%lld %lld %d", &arr[i].ai, &arr[i].bi, &m); 46 while (m--) 47 { 48 int tmp = 0; 49 scanf("%d", &tmp); 50 S += (1 << (tmp - 1)); 51 } 52 arr[i].state = S; 53 } 54 ll ans = DFS(1, 0); 55 printf("%lld\n", ans); 56 } 57 } 58 59 int main() 60 { 61 #ifdef LOCAL_JUDGE 62 freopen("Text.txt", "r", stdin); 63 #endif // LOCAL_JUDGE 64 65 RUN(); 66 67 #ifdef LOCAL_JUDGE 68 fclose(stdin); 69 #endif // LOCAL_JUDGE 70 71 return 0; 72 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N (1 << 21) 5 #define ll long long 6 7 struct node 8 { 9 ll a, b; 10 int sta; 11 inline void scan() 12 { 13 int tot, k; sta = 0; 14 scanf("%lld%lld%d", &a, &b, &tot); 15 while (tot--) 16 { 17 scanf("%d", &k); 18 sta |= (1 << (k - 1)); 19 } 20 } 21 }arr[25]; 22 23 int n; 24 ll dp[N]; 25 26 inline ll Count(int x) 27 { 28 int res = 0; 29 while (x) 30 { 31 ++res; 32 x &= (x - 1); 33 } 34 return res; 35 } 36 37 inline void Run() 38 { 39 while (scanf("%d", &n) != EOF) 40 { 41 for (int i = 1; i <= n; ++i) arr[i].scan(); 42 memset(dp, -1, sizeof dp); 43 ll ans = 0; dp[0] = 0; 44 for (int i = 0; i < (1 << n); ++i) 45 { 46 if (dp[i] == -1) continue; 47 for (int j = 1; j <= n; ++j) 48 { 49 if (!(i & (1 << (j - 1))) && (i & (arr[j].sta)) == arr[j].sta) 50 { 51 int tmp = i | (1 << (j - 1)); 52 ll t = Count(tmp); 53 dp[tmp] = max(dp[tmp], dp[i] + arr[j].a * t + arr[j].b); 54 ans = max(ans, dp[tmp]); 55 } 56 } 57 } 58 printf("%lld\n", ans); 59 } 60 } 61 62 int main() 63 { 64 #ifdef LOCAL 65 freopen("Test.in", "r", stdin); 66 #endif 67 68 Run(); 69 return 0; 70 }
F. An Easy Problem On The Trees
留坑。
G. Lpl and Energy-saving Lamps
题意:有n个房间,每次按顺序换灯泡,一个房间要不所有灯泡都换,要不一个都不换,每个月有固定的新灯泡数,没还完留到下个月,询问第几个月能够换掉几个房间以及剩下的房间数
思路:线段树维护一个最小值,预处理答案
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define INF 0x3f3f3f3f 6 #define ll long long 7 8 typedef pair <int, int> pii; 9 10 int n, m, q, sum; 11 int arr[N]; 12 pii ans[N]; 13 14 struct node 15 { 16 int l, r, cnt; 17 int Min, sum; 18 inline node() {} 19 inline node(int _l, int _r) 20 { 21 l = _l, r = _r; 22 Min = sum = 0; 23 } 24 }tree[N << 2]; 25 26 inline void pushup(int id) 27 { 28 tree[id].Min = min(tree[id << 1].Min, tree[id << 1 | 1].Min); 29 tree[id].sum = tree[id << 1].sum + tree[id << 1 | 1].sum; 30 tree[id].cnt = tree[id << 1].cnt + tree[id << 1 | 1].cnt; 31 } 32 33 inline void build(int id, int l, int r) 34 { 35 tree[id] = node(l, r); 36 if (l == r) 37 { 38 tree[id].Min = tree[id].sum = arr[l]; 39 tree[id].cnt = 1; 40 return; 41 } 42 int mid = (l + r) >> 1; 43 build(id << 1, l, mid); 44 build(id << 1 | 1, mid + 1, r); 45 pushup(id); 46 } 47 48 int anssum, remind; 49 50 inline void query(int id) 51 { 52 if (tree[id].Min <= remind && tree[id].sum <= remind) 53 { 54 anssum += tree[id].cnt; 55 sum -= tree[id].sum; 56 remind -= tree[id].sum; 57 tree[id].Min = INF; 58 tree[id].sum = 0; 59 tree[id].cnt = 0; 60 return; 61 } 62 if (tree[id << 1].Min <= remind) query(id << 1); 63 if (tree[id << 1 | 1].Min <= remind) query(id << 1 | 1); 64 pushup(id); 65 } 66 67 inline void out(int x) 68 { 69 if (x / 10) out(x / 10); 70 putchar(x % 10 + '0'); 71 } 72 73 inline void Run() 74 { 75 while (scanf("%d%d", &n, &m) != EOF) 76 { 77 memset(ans, 0, sizeof ans); sum = 0; 78 for (int i = 1; i <= n; ++i) scanf("%d", arr + i), sum += arr[i]; 79 build(1, 1, n); remind = m; 80 for (int i = 1; i <= 100000; ++i, remind += m) 81 { 82 if (sum == 0) 83 { 84 ans[i] = ans[i - 1]; 85 continue; 86 } 87 anssum = 0; query(1); 88 ans[i].first = ans[i - 1].first + anssum; 89 ans[i].second = remind; 90 } 91 scanf("%d", &q); 92 for (int i = 1, x; i <= q; ++i) 93 { 94 scanf("%d", &x); 95 out(ans[x].first); putchar(' '); 96 out(ans[x].second); putchar('\n'); 97 } 98 } 99 } 100 101 int main() 102 { 103 #ifdef LOCAL 104 freopen("Test.in", "r", stdin); 105 #endif 106 107 Run(); 108 return 0; 109 }
H. Set
留坑。
I. Skr
留坑。
J. Sum
题意:定义$F[n] = 有多少个n = ab$ a 和 b 都不能是平方数的倍数 1 除外 求 $\sum_{i = 1} ^ {i = n} F[n]$
思路:枚举每个素数,对于拥有不同质因子的数,权值成2,对于拥有两个相同的质因子的数,权值除以2,对于拥有三个或者三个以上质因子的数,权值为零,最后求和。(卡常)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const int maxn = 2e7 + 5; 6 7 int n; 8 int tot; 9 int isprime[maxn]; 10 int prime[maxn]; 11 int a[maxn]; 12 int ans[maxn]; 13 14 inline void Init_prime() 15 { 16 tot = 1; 17 prime[1] = 1; 18 a[1] = 1; 19 ans[1] = 1; 20 for (register int i = 2; i < maxn; ++i) 21 { 22 a[i] = 1; 23 if (!isprime[i]) 24 { 25 prime[tot++] = i; 26 27 } 28 for (register int j = 1; j < tot && i * prime[j] < maxn; ++j) 29 { 30 isprime[i * prime[j]] = 1; 31 if (!(i % prime[j])) 32 { 33 break; 34 } 35 } 36 } 37 for (register int i = 1; i < tot; ++i) 38 { 39 for (register int j = 1; j * prime[i] < maxn; ++j) 40 { 41 a[j * prime[i]] <<= 1; 42 } 43 if (prime[i] > maxn / prime[i]) continue; 44 for (register int j = 1; j * prime[i] * prime[i] < maxn; ++j) 45 { 46 if (j % prime[i] == 0) 47 { 48 a[j * prime[i] * prime[i]] = 0; 49 } 50 a[j * prime[i] * prime[i]] >>= 1; 51 } 52 } 53 for (register int i = 1; i < maxn; ++i) 54 { 55 ans[i] = ans[i - 1] + a[i]; 56 } 57 } 58 59 int main() 60 { 61 Init_prime(); 62 int t; 63 //cout << tot << endl; 64 scanf("%d", &t); 65 while (t--) 66 { 67 scanf("%d", &n); 68 printf("%d\n", ans[n]); 69 } 70 return 0; 71 }
K. The Great Nim Game
留坑。
L. Magical Girl Haze
题意:有n个城市,m条边,可以令k条路权值为0,求1 - n 的最短路
思路:对于每个城市,枚举到这个城市,免费0-k次的权值,跑一个(立体的?)最短路
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define ll long long 6 #define INFLL 0x3f3f3f3f3f3f3f3f 7 8 struct Edge 9 { 10 int to, nx; ll w; 11 inline Edge() {} 12 inline Edge(int to, int nx, ll w) : to(to), nx(nx), w(w) {} 13 }edge[N << 1]; 14 15 int head[N], pos; 16 17 inline void Init() 18 { 19 memset(head, -1, sizeof head); 20 pos = 0; 21 } 22 23 inline void addedge(int u, int v, ll w) 24 { 25 edge[++pos] = Edge(v, head[u], w); head[u] = pos; 26 } 27 28 struct node 29 { 30 int to, p; ll w; 31 inline node() {} 32 inline node(int to, int p, ll w) : to(to), p(p), w(w) {} 33 inline bool operator < (const node &r) const 34 { 35 return w > r.w; 36 } 37 }; 38 39 ll dist[N][20]; 40 bool used[N][20]; 41 int t, n, m, k; 42 43 inline void Dijkstra() 44 { 45 for (int i = 1; i <= n; ++i) for (int j = 0; j <= k; ++j) dist[i][j] = INFLL, used[i][j] = false; 46 priority_queue <node> q; q.emplace(1, 0, 0); dist[1][0] = 0; 47 while (!q.empty()) 48 { 49 int u = q.top().to; 50 int p = q.top().p; 51 ll w = q.top().w; 52 //cout << w << endl; 53 q.pop(); 54 if (used[u][p]) continue; 55 used[u][p] = true; 56 dist[u][p] = w; 57 for (int i = head[u]; ~i; i = edge[i].nx) 58 { 59 int v = edge[i].to; 60 ll c = edge[i].w; 61 if (dist[u][p] + c < dist[v][p]) 62 { 63 dist[v][p] = dist[u][p] + c; 64 q.emplace(v, p, dist[v][p]); 65 } 66 if (p + 1 <= k && dist[u][p] < dist[v][p + 1]) 67 { 68 dist[v][p + 1] = dist[u][p]; 69 q.emplace(v, p + 1, dist[v][p + 1]); 70 } 71 } 72 } 73 } 74 75 76 inline void Run() 77 { 78 scanf("%d", &t); 79 while (t--) 80 { 81 Init(); 82 scanf("%d%d%d", &n, &m, &k); 83 int u, v; ll w; 84 for (int i = 1; i <= m; ++i) 85 { 86 scanf("%d%d%lld", &u, &v, &w); 87 addedge(u, v, w); 88 } 89 Dijkstra(); 90 ll ans = dist[n][k]; 91 printf("%lld\n", ans); 92 } 93 } 94 int main() 95 { 96 #ifdef LOCAL 97 freopen("Test.in", "r", stdin); 98 #endif 99 100 Run(); 101 102 return 0; 103 }