ZOJ Monthly, January 2018 Solution
A - Candy Game
水。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 1010 5 int t, n; 6 int a[N], b[N]; 7 8 int main() 9 { 10 scanf("%d", &t); 11 while (t--) 12 { 13 scanf("%d", &n); 14 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 15 for (int i = 1; i <= n; ++i) scanf("%d", b + i); 16 puts(accumulate(a + 1, a + n + 1, 0) > accumulate(b + 1, b + 1 + n, 0) ? "BaoBao" : "DreamGrid"); 17 } 18 return 0; 19 }
B - PreSuffix
留坑。
C - An Unsure Catch
留坑。
D - Seat Assignment
题意:给出10个数,分别表示有几个人愿意坐在编号为$i$的倍数的位置上,有m个位置,编号为1-m, 求最多坐下多少人
思路:通过暴力枚举发现在1-10的lcm2050范围内只有48种情况,网络流可以是左边十个点, 右边48个点,最大流跑一跑
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e4 + 10; 6 const int INF = 0x3f3f3f3f; 7 8 9 struct Edge{ 10 int from; 11 int to; 12 int cap; 13 int flow; 14 Edge(){} 15 Edge(int from, int to, int cap, int flow) :from(from), to(to), cap(cap), flow(flow){} 16 }; 17 18 int S, T; 19 vector<Edge>edge; 20 vector<int>G[maxn]; 21 int arr[maxn]; 22 int vis[maxn]; 23 int d[maxn]; 24 int cur[maxn]; 25 int cnt; 26 int mark[maxn]; 27 int limit[maxn]; 28 int number[maxn]; 29 30 void Init() 31 { 32 edge.clear(); 33 for(int i = 0; i < 100; ++i) G[i].clear(); 34 } 35 36 void addedge(int from, int to, int cap) 37 { 38 edge.push_back(Edge(from, to, cap, 0)); 39 edge.push_back(Edge(to, from, 0, 0)); 40 int len = edge.size(); 41 G[from].push_back(len - 2); 42 G[to].push_back(len - 1); 43 } 44 45 bool BFS() 46 { 47 memset(d, 0, sizeof d); 48 memset(vis, 0, sizeof vis); 49 queue<int>q; 50 q.push(S); 51 d[S] = 1; 52 vis[S] = 1; 53 while(!q.empty()) 54 { 55 int x = q.front(); 56 q.pop(); 57 for(int i = 0, len = G[x].size(); i < len; ++i) 58 { 59 Edge &e = edge[G[x][i]]; 60 if(!vis[e.to] && e.cap > e.flow) 61 { 62 vis[e.to] = 1; 63 d[e.to] = d[x] + 1; 64 q.push(e.to); 65 } 66 } 67 } 68 return vis[T]; 69 } 70 71 int DFS(int x, int a) 72 { 73 if(x == T || a == 0) return a; 74 int flow = 0; 75 int f; 76 for(int &i = cur[x]; i < G[x].size(); ++i) 77 { 78 Edge &e = edge[G[x][i]]; 79 if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) 80 { 81 e.flow += f; 82 edge[G[x][i] ^ 1].flow -= f; 83 flow += f; 84 a -= f; 85 if(a == 0) break; 86 } 87 } 88 return flow; 89 } 90 91 int dicnic() 92 { 93 int ans = 0; 94 while(BFS()) 95 { 96 memset(cur, 0, sizeof cur); 97 ans += DFS(S, INF); 98 } 99 return ans; 100 } 101 102 void init() 103 { 104 cnt = 0; 105 for(int i = 0; i < 2520; ++i) 106 { 107 int S = 0; 108 for(int j = 1; j <= 10; ++j) 109 { 110 if(i % j == 0) S |= (1 << j); 111 } 112 if(!vis[S]) 113 { 114 cnt++; 115 vis[S] = cnt; 116 number[cnt] = S; 117 } 118 mark[i] = vis[S]; 119 } 120 } 121 122 123 int main() 124 { 125 init(); 126 int t; 127 scanf("%d", &t); 128 while(t--) 129 { 130 int n; 131 scanf("%d", &n); 132 Init(); 133 memset(limit, 0, sizeof limit); 134 S = 0, T = 59; 135 for(int i = 0; i < 2520; ++i) 136 { 137 int num = n / 2520; 138 if(i >= 1 && n % 2520 >= i) num++; 139 limit[mark[i]] += num; 140 } 141 for(int i = 1; i <= 48; ++i) 142 { 143 addedge(i + 10, T, limit[i]); 144 } 145 for(int i = 1; i <= 10; ++i) 146 { 147 scanf("%d", arr + i); 148 if(arr[i]) 149 { 150 addedge(S, i, arr[i]); 151 for(int j = 1; j <= 48; ++j) 152 { 153 if(number[j] & (1 << i)) 154 { 155 addedge(i, j + 10, arr[i]); 156 } 157 } 158 } 159 } 160 int ans = dicnic(); 161 printf("%d\n", ans); 162 } 163 }
E - Yet Another Data Structure Problem
题意:三种操作,一种是区间乘一个数v,一种是把区间内每个数都变成其k次方,还有一种是求区间乘积
思路:增加两个lazy操作,一种是幂次,一种是乘数
更新幂次的时候顺带把乘积更新一下
再考虑费马小定理 把幂次$模(MOD - 1)$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define ll long long 6 const ll MOD = (ll)1e9 + 7; 7 int t, n, q; 8 ll arr[N]; 9 10 ll qmod(ll base, ll n) 11 { 12 ll res = 1; 13 while (n) 14 { 15 if (n & 1) res = res * base % MOD; 16 base = base * base % MOD; 17 n >>= 1; 18 } 19 return res; 20 } 21 22 struct SEG 23 { 24 ll lazy[N << 2][2], mul[N << 2]; 25 void pushup(int id) { mul[id] = (mul[id << 1] * mul[id << 1 | 1]) % MOD; } 26 void build(int id, int l, int r) 27 { 28 lazy[id][0] = 1; lazy[id][1] = 1; 29 if (l == r) 30 { 31 mul[id] = arr[l]; 32 return; 33 } 34 int mid = (l + r) >> 1; 35 build(id << 1, l, mid); 36 build(id << 1 | 1, mid + 1, r); 37 pushup(id); 38 } 39 void pushdown(int id, int l, int r) 40 { 41 if (lazy[id][1] != 1) 42 { 43 lazy[id << 1][1] = (lazy[id << 1][1] * lazy[id][1]) % (MOD - 1); 44 lazy[id << 1][0] = qmod(lazy[id << 1][0], lazy[id][1]); 45 mul[id << 1] = qmod(mul[id << 1], lazy[id][1]); 46 lazy[id << 1 | 1][1] = (lazy[id << 1 | 1][1] * lazy[id][1]) % (MOD - 1); 47 lazy[id << 1 | 1][0] = qmod(lazy[id << 1 | 1][0], lazy[id][1]); 48 mul[id << 1 | 1] = qmod(mul[id << 1 | 1], lazy[id][1]); 49 lazy[id][1] = 1; 50 } 51 if (lazy[id][0] != 1) 52 { 53 int mid = (l + r) >> 1; 54 lazy[id << 1][0] = (lazy[id << 1][0] * lazy[id][0]) % MOD; 55 mul[id << 1] = (mul[id << 1] * qmod(lazy[id][0], (mid - l + 1))) % MOD; 56 lazy[id << 1 | 1][0] = (lazy[id << 1 | 1][0] * lazy[id][0]) % MOD; 57 mul[id << 1 | 1] = (mul[id << 1 | 1] * qmod(lazy[id][0], (r - mid))) % MOD; 58 lazy[id][0] = 1; 59 } 60 } 61 void update0(int id, int l, int r, int ql, int qr, ll v) 62 { 63 if (l >= ql && r <= qr) 64 { 65 lazy[id][0] = (lazy[id][0] * v) % MOD; 66 mul[id] = (mul[id] * qmod(v, (r - l + 1))) % MOD; 67 return; 68 } 69 pushdown(id, l, r); 70 int mid = (l + r) >> 1; 71 if (ql <= mid) update0(id << 1, l, mid, ql, qr, v); 72 if (qr > mid) update0(id << 1 | 1, mid + 1, r, ql, qr, v); 73 pushup(id); 74 } 75 void update1(int id, int l, int r, int ql, int qr, ll v) 76 { 77 if (l >= ql && r <= qr) 78 { 79 lazy[id][0] = qmod(lazy[id][0], v); 80 mul[id] = qmod(mul[id], v); 81 lazy[id][1] = (lazy[id][1] * v) % (MOD - 1); 82 return; 83 } 84 pushdown(id, l, r); 85 int mid = (l + r) >> 1; 86 if (ql <= mid) update1(id << 1, l, mid, ql, qr, v); 87 if (qr > mid) update1(id << 1 | 1, mid + 1, r, ql, qr, v); 88 pushup(id); 89 } 90 ll query(int id, int l, int r, int ql, int qr) 91 { 92 if (l >= ql && r <= qr) return mul[id]; 93 pushdown(id, l, r); 94 int mid = (l + r) >> 1; 95 ll res = 1; 96 if (ql <= mid) res = (res * query(id << 1, l, mid, ql, qr)) % MOD; 97 if (qr > mid) res = (res * query(id << 1 | 1, mid + 1, r, ql, qr)) % MOD; 98 pushup(id); 99 return res; 100 } 101 }seg; 102 103 int main() 104 { 105 scanf("%d", &t); 106 while (t--) 107 { 108 scanf("%d%d", &n, &q); 109 for (int i = 1; i <= n; ++i) scanf("%lld", arr + i); 110 seg.build(1, 1, n); 111 for (int i = 1, op, l, r, v; i <= q; ++i) 112 { 113 scanf("%d%d%d", &op, &l, &r); 114 if (op == 3) printf("%lld\n", seg.query(1, 1, n, l, r)); 115 else 116 { 117 scanf("%d", &v); 118 if (op == 1) seg.update0(1, 1, n, l, r, v); 119 else seg.update1(1, 1, n, l, r, v); 120 } 121 } 122 } 123 return 0; 124 }
F - The Limit
题意:给出两个多项式,求极限
思路:四种情况,分别讨论即可。注意字符串的处理,以及最后负号的判断
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 int t; ll x; 6 struct node 7 { 8 ll a[20]; 9 void scan() 10 { 11 memset(a, 0, sizeof a); 12 string s; cin >> s; 13 if (s[0] != '-') s.insert(0, "+"); 14 while (1) 15 { 16 bool flag = 0; 17 for (int i = 0, len = s.size(); i < len; ++i) 18 { 19 if (s[i] == 'x' && (i == len - 1 || s[i + 1] != '^')) 20 { 21 s.insert(i + 1, "^1"); 22 flag = 1; 23 break; 24 } 25 } 26 if (!flag) break; 27 } 28 while (1) 29 { 30 bool flag = 0; 31 for (int i = 0, len = s.size(); i < len; ++i) 32 { 33 if (isdigit(s[i]) && (s[i - 1] == '+' || s[i - 1] == '-') && (i == len - 1 || s[i + 1] == '+' || s[i + 1] == '-')) 34 { 35 s.insert(i + 1, "x^0"); 36 flag = 1; 37 break; 38 } 39 } 40 if (!flag) break; 41 } 42 while (1) 43 { 44 bool flag = 0; 45 for (int i = 0, len = s.size(); i < len; ++i) 46 { 47 if (s[i] == 'x' && !isdigit(s[i - 1])) 48 { 49 s.insert(i, "1"); 50 flag = 1; 51 break; 52 } 53 } 54 if (!flag) break; 55 } 56 for (int i = 0, len = s.size(); i < len; ++i) 57 { 58 if (s[i] == '^') 59 { 60 int pos = s[i + 1] - '0'; 61 int base = (s[i - 2] - '0') * (s[i - 3] == '+' ? 1 : -1); 62 a[pos] += base; 63 } 64 } 65 } 66 ll calc() 67 { 68 ll res = 0; 69 ll base = 1; 70 for (int i = 0; i <= 9; ++i, base *= x) 71 res += base * a[i]; 72 return res; 73 } 74 void luo() 75 { 76 for (int i = 0; i < 9; ++i) 77 a[i] = a[i + 1] * (ll)(i + 1); 78 } 79 80 }fenzi, fenmu; 81 82 ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } 83 84 void solve() 85 { 86 while (1) 87 { 88 ll a = fenzi.calc(), b = fenmu.calc(); 89 if (a == 0 && b == 0) 90 { 91 fenzi.luo(); 92 fenmu.luo(); 93 } 94 else if (a == 0) 95 { 96 cout << "0\n"; 97 return; 98 } 99 else if (b == 0) 100 { 101 cout << "INF\n"; 102 return; 103 } 104 else if (a && b) 105 { 106 int vis = (a < 0 || b < 0) && !(a < 0 && b < 0); 107 a = abs(a), b = abs(b); 108 ll GCD = gcd(a, b); 109 a /= GCD, b /= GCD; 110 if (vis) cout << "-"; 111 if (b == 1) 112 cout << a << "\n"; 113 else 114 cout << a << "/" << b << "\n"; 115 return; 116 } 117 } 118 } 119 120 int main() 121 { 122 ios::sync_with_stdio(false); 123 cin.tie(0); 124 cout.tie(0); 125 cin >> t; 126 while (t--) 127 { 128 fenzi.scan(); 129 fenmu.scan(); 130 cin >> x; 131 solve(); 132 } 133 return 0; 134 }
G - It's High Noon
留坑。
H - Traveling Plan
题意:有些城市有补给,有些没有,经过一条路要消耗这条路的边权的补给,每次询问两个补给点,需要多大容量的背包
思路:先将所有补给点作源点跑最短路,然后更新每条边权为这条边本身的边权加两个端点到最近的补给点的距离,然后求最小生成树
倍增维护最大
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 const ll INFLL = 0x3f3f3f3f3f3f3f3f; 7 const int maxn = 2e5 + 10; 8 const int DEG = 20; 9 10 struct qnode{ 11 int to; 12 ll val; 13 qnode(){} 14 qnode(int to, ll val) :to(to), val(val){} 15 bool operator < (const qnode &b) const 16 { 17 return val > b.val; 18 } 19 }; 20 21 struct node{ 22 int u, v; 23 ll w; 24 bool operator < (const node &b) const 25 { 26 return w < b.w; 27 } 28 }tmp[maxn << 1]; 29 30 struct Edge{ 31 int to, nxt; 32 ll w; 33 Edge(){} 34 Edge(int to, int nxt, ll w) : to(to), nxt(nxt), w(w){} 35 }edge[maxn << 1]; 36 37 int n, m; 38 int fa[maxn][DEG]; 39 int deg[maxn]; 40 ll dist[maxn][DEG]; 41 vector<qnode>G[maxn]; 42 int vis[maxn]; 43 int head[maxn]; 44 ll dis[maxn]; 45 int tot; 46 priority_queue<qnode>q; 47 int father[maxn]; 48 49 void Init(int N) 50 { 51 for(int i = 1; i <= N; ++i) 52 { 53 dis[i] = INFLL; 54 father[i] = i; 55 head[i] = -1; 56 G[i].clear(); 57 } 58 tot = 0; 59 } 60 int find(int x) 61 { 62 return x == father[x] ? father[x] : father[x] = find(father[x]); 63 } 64 65 bool same(int x,int y) 66 { 67 return find(x) == find(y); 68 } 69 70 void mix(int x, int y) 71 { 72 x = find(x); 73 y = find(y); 74 if(x != y) 75 { 76 father[x] = y; 77 } 78 } 79 80 void addedge(int u, int v, ll w) 81 { 82 edge[tot] = Edge(v, head[u], w); head[u] = tot++; 83 edge[tot] = Edge(u, head[v], w); head[v] = tot++; 84 } 85 86 void Dijkstra() 87 { 88 while(!q.empty()) 89 { 90 qnode tmp = q.top(); 91 q.pop(); 92 int u = tmp.to; 93 if(tmp.val > dis[u]) continue; 94 for(int i = 0, len = G[u].size(); i < len; ++i) 95 { 96 int v = G[u][i].to; 97 ll cost = G[u][i].val; 98 if(dis[v] > dis[u] + cost) 99 { 100 dis[v] = dis[u] + cost; 101 q.push(qnode(v, dis[v])); 102 } 103 } 104 } 105 } 106 107 void BFS(int root) 108 { 109 queue<int>que; 110 deg[root] = 0; 111 fa[root][0] = root; 112 dist[root][0] = 0; 113 que.push(root); 114 while(!que.empty()) 115 { 116 int tmp = que.front(); 117 que.pop(); 118 for(int i = 1; i < DEG; ++i) 119 { 120 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 121 dist[tmp][i] = max(dist[tmp][i - 1], dist[fa[tmp][i - 1]][i - 1]); 122 } 123 for(int i = head[tmp]; ~i; i = edge[i].nxt) 124 { 125 int v = edge[i].to; 126 if(v == fa[tmp][0]) continue; 127 deg[v] = deg[tmp] + 1; 128 dist[v][0] = edge[i].w; 129 fa[v][0] = tmp; 130 que.push(v); 131 } 132 } 133 } 134 135 ll LCA(int u, int v) 136 { 137 ll res = 0; 138 if(deg[u] > deg[v]) swap(u, v); 139 int hu = deg[u], hv = deg[v]; 140 int tu = u, tv = v; 141 for(int det = hv - hu, i = 0; det; det >>= 1, ++i) 142 { 143 if(det & 1) 144 { 145 res = max(res, dist[tv][i]); 146 tv = fa[tv][i]; 147 } 148 } 149 if(tu == tv) return res; 150 for(int i = DEG - 1; i >= 0; --i) 151 { 152 if(fa[tu][i] == fa[tv][i]) continue; 153 res = max(res, dist[tu][i]); 154 res = max(res, dist[tv][i]); 155 tu = fa[tu][i]; 156 tv = fa[tv][i]; 157 } 158 return max(res, max(dist[tu][0], dist[tv][0])); 159 } 160 161 int main() 162 { 163 while(~scanf("%d %d", &n, &m)) 164 { 165 Init(n); 166 int root; 167 for(int i = 1; i <= n; ++i) 168 { 169 scanf("%d", vis + i); 170 if(vis[i] == 1) 171 { 172 dis[i] = 0; 173 q.push(qnode(i, 0)); 174 } 175 else root = i; 176 } 177 for(int i = 1; i <= m; ++i) 178 { 179 scanf("%d %d %lld", &tmp[i].u, &tmp[i].v, &tmp[i].w); 180 G[tmp[i].u].push_back(qnode(tmp[i].v, tmp[i].w)); 181 G[tmp[i].v].push_back(qnode(tmp[i].u, tmp[i].w)); 182 } 183 Dijkstra(); 184 // for(int i = 1; i <= n; ++i) cout << i << " " << dis[i] << endl; 185 for(int i = 1; i <= m; ++i) tmp[i].w += dis[tmp[i].u] + dis[tmp[i].v]; 186 sort(tmp + 1, tmp + 1 + m); 187 for(int i = 1; i <= m; ++i) 188 { 189 if(same(tmp[i].u, tmp[i].v)) continue; 190 mix(tmp[i].u, tmp[i].v); 191 addedge(tmp[i].u, tmp[i].v, tmp[i].w); 192 } 193 BFS(root); 194 int q; 195 scanf("%d", &q); 196 while(q--) 197 { 198 int u, v; 199 scanf("%d %d", &u, &v); 200 ll ans = LCA(u, v); 201 printf("%lld\n", ans); 202 } 203 } 204 return 0; 205 }
I - Wooden Bridge
留坑。
J - Distance
题意:定义多维空间的距离为$\sum |a_i - b_i|^p$ 求有多少x的子串和y的子串形成的坐标的距离小于v 子串长度要相同
思路:固定x起点,双指针找y的两个端点
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 const int maxn = 1e3 + 10; 7 8 int n, p; 9 ll V; 10 ll arr[maxn], brr[maxn]; 11 ll cnt[maxn << 1], val[maxn << 1]; 12 13 ll calc(int i, int j) 14 { 15 ll tmp = abs(arr[i] - brr[j]); 16 ll res = 1; 17 for(int i = 1; i <= p; ++i) res = res * tmp; 18 return res; 19 } 20 21 int main() 22 { 23 int t; 24 scanf("%d", &t); 25 while(t--) 26 { 27 scanf("%d %lld %d", &n ,&V ,&p); 28 memset(cnt, 0, sizeof cnt); 29 memset(val, 0, sizeof val); 30 for(int i = 1; i <= n; ++i) scanf("%lld", arr + i); 31 for(int i = 1; i <= n; ++i) scanf("%lld", brr + i); 32 ll ans = 0; 33 for(int i = 1; i <= n; ++i) 34 { 35 for(int j = 1; j <= n; ++j) 36 { 37 int tmp = i - j + n; 38 cnt[tmp]++; 39 val[tmp] += calc(i, j); 40 while(cnt[tmp] > 0 && val[tmp] > V) 41 { 42 cnt[tmp]--; 43 val[tmp] -= calc(i - cnt[tmp], j - cnt[tmp]); 44 } 45 ans += cnt[tmp]; 46 } 47 } 48 printf("%lld\n", ans); 49 } 50 return 0; 51 }