2017-2018 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) Solution
A - Odd Palindrome
水。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 110 6 7 char s[N]; 8 9 inline bool work() 10 { 11 int len = strlen(s); 12 for (int i = 1; i < len; ++i) 13 { 14 if (s[i] == s[i - 1]) return false; 15 } 16 return true; 17 } 18 19 int main() 20 { 21 while (scanf("%s", s) != EOF) 22 { 23 puts(work() ? "Odd." : "Or not."); 24 } 25 return 0; 26 }
B - Enlarging Enthusiasm
留坑。
C - Fear Factoring
题意:定义$F(n)$ 为 n的约数和 求 $S = \sum_{a <= n <= b} F(n)$
思路:对于1-$\sqrt(b)$内的因数可以进行枚举。对于大于$\sqrt(b)$的因数,在枚举1-sqrt(b)的因数i的时候,a-b内的(a-1)/i, b/i是一段连续的数,通过求和公式即可得到
![](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 a,b; 8 9 int main() 10 { 11 while(~scanf("%lld %lld", &a, &b)) 12 { 13 if(a > b) swap(a, b); 14 ll tmp = sqrt(b); 15 ll ans = 0; 16 for(ll i = 1; i <= tmp; ++i) 17 { 18 ans += i * (b / i - (a - 1) / i); 19 ll tmp1 = max(tmp, (a - 1) / i); 20 ll tmp2 = max(tmp, b / i); 21 ans += (tmp2 - tmp1) * (tmp1 + tmp2 + 1) / 2; 22 } 23 printf("%lld\n", ans); 24 } 25 return 0; 26 }
D - Rainbow Roads
题意:彩虹:一条路径当中,相邻的两条边,权值都不同 好点:以某个点为端点的所有简单路径当中,都是彩虹。 求一棵树当中有多少个好点
思路:两种情况
1° DFS下去碰到相邻的两条边,那么这两条边的最上面的那个点上面的其他所有点都不是好点,这两条边最下面那个点的子树的所有点,都不是好点
2°以某个点为根的子树中,有两个直系儿子的边权相同,那么这两个儿子的子树的所有点都不是好点
DFS序 区间标记
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 50010 6 7 struct node{ 8 int v; 9 int c; 10 inline node(){} 11 inline node(int v,int c) :v(v),c(c){} 12 inline bool operator < (const node &b) const 13 { 14 return c < b.c; 15 } 16 }; 17 18 int n; 19 vector<node>G[N]; 20 int fa[N]; 21 int son[N]; 22 int ord[N]; 23 int dro[N]; 24 int arr[N]; 25 int cnt; 26 27 inline void Init() 28 { 29 cnt = 0; 30 memset(arr, 0, sizeof arr); 31 for(int i = 1; i <= n; ++i) 32 { 33 G[i].clear(); 34 } 35 } 36 37 inline void DFS(int u,int pre) 38 { 39 fa[u] = pre; 40 ord[u] = ++cnt; 41 dro[cnt] = u; 42 son[u] = 1; 43 for(auto it : G[u]) 44 { 45 int v = it.v; 46 if(v == pre) continue; 47 DFS(v, u); 48 son[u] += son[v]; 49 } 50 } 51 52 int main() 53 { 54 while(~scanf("%d", &n)) 55 { 56 Init(); 57 for(int i = 1; i < n; ++i) 58 { 59 int u, v, c; 60 scanf("%d %d %d", &u, &v, &c); 61 G[u].push_back(node(v, c)); 62 G[v].push_back(node(u, c)); 63 } 64 DFS(1, -1); 65 for(int i = 1; i <= n; ++i) 66 { 67 sort(G[i].begin(), G[i].end()); 68 int len = G[i].size(); 69 int it = 0; 70 for(int j = it; j < len; j = it) 71 { 72 ++it; 73 while(it < len && G[i][it].c == G[i][j].c) 74 { 75 ++it; 76 } 77 if(it > j + 1) 78 { 79 for(int k = j; k < it; ++k) 80 { 81 int v = G[i][k].v; 82 if(v == fa[i]) 83 { 84 ++arr[ord[1]]; 85 --arr[ord[i]]; 86 ++arr[ord[i] + son[i]]; 87 } 88 else 89 { 90 ++arr[ord[v]]; 91 --arr[ord[v] + son[v]]; 92 } 93 } 94 } 95 } 96 } 97 for(int i = 1; i <= n; ++i) 98 { 99 arr[i] += arr[i - 1]; 100 } 101 vector<int>vec; 102 for(int i = 1; i <= n; ++i) 103 { 104 if(arr[i] == 0) 105 { 106 vec.push_back(dro[i]); 107 } 108 } 109 int len = vec.size(); 110 sort(vec.begin(), vec.end()); 111 printf("%d\n", len); 112 for(int i = 0; i < len; ++i) 113 { 114 printf("%d\n",vec[i]); 115 } 116 } 117 return 0; 118 }
E - Straight Shot
题意:一个机器人,给定初始速度,问从(0,0)到(0,x)。在这段路程上存在沿着y轴方向滑动的部分街道
思路:对v进行正交分解后,很容易发现vy=$\sum_{l <= i <= n } (r - l) * vi$ 从而得到了vy,在进行计算vx,从而得到时间。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 double x, v, vy; 6 double l, r, vi, tmp; 7 8 int n; 9 10 int main() 11 { 12 while(~scanf("%d %lf %lf", &n, &x, &v)) 13 { 14 tmp = 0; 15 for(int i = 1; i <= n; ++i) 16 { 17 scanf("%lf %lf %lf", &l, &r, &vi); 18 tmp += (r - l) * vi; 19 } 20 vy = tmp / x; 21 if(fabs(vy) > v) 22 { 23 puts("Too hard"); 24 } 25 else 26 { 27 double vx = sqrt(v * v - vy * vy); 28 double ans = x / vx; 29 printf("%.3f\n", ans); 30 } 31 } 32 return 0; 33 }
F - Distinct Distances
留坑。
G - Security Badge
留坑。
H - Avoiding Airports
留坑。
I - Long Long Strings
题意:有两个长度为$10_10$的DNA序列,刚开始相同,有两类操作,一种是添加,一种是删除,求两个DNA序列经过一系列操作后是否相同
思路:维护两个东西,一个是新添加的坐标,一个是在原序列中删除的坐标
新添加的话,那么在它之前添加的坐标大于等于它的都要后移一位
删除的话,如果是删除的新添加的,就直接删除,要注意新添加的坐标在它后面的都要前移一位
如果是在原序列中删除,要考虑删除的坐标是原来在它之前新添加的,要后移一位,还有在它之前的删除的都要加上
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 6 typedef pair <ll, char> plc; 7 8 vector <ll> Del[2]; 9 vector <plc> Ins[2]; 10 char s[10]; ll num; char c; 11 12 inline bool Dell(int vis, ll num) 13 { 14 for (int i = 0, len = Ins[vis].size(); i < len; ++i) if (Ins[vis][i].first == num) 15 { 16 Ins[vis].erase(Ins[vis].begin() + i); 17 for (auto &it : Ins[vis]) if (it.first >= num) 18 --it.first; 19 return true; 20 } 21 return false; 22 } 23 24 inline void Delll(int vis) 25 { 26 ll tmp = num; 27 for (auto &it : Ins[vis]) 28 { 29 if (num >= it.first) 30 --tmp; 31 else 32 --it.first; 33 } 34 for (auto it : Del[vis]) 35 { 36 if (it <= tmp) 37 ++tmp; 38 else 39 break; 40 } 41 num = tmp; 42 } 43 44 inline void work(int vis) 45 { 46 Ins[vis].clear(); Del[vis].clear(); 47 while (scanf("%s", s), s[0] != 'E') 48 { 49 scanf("%lld", &num); 50 if (s[0] == 'I') 51 { 52 scanf(" %c", &c); 53 for (auto &it : Ins[vis]) if (it.first >= num) 54 ++it.first; 55 Ins[vis].emplace_back(num, c); 56 for (int len = Ins[vis].size(), i = len - 1; i >= 1; --i) if (Ins[vis][i].first < Ins[vis][i - 1].first) 57 swap(Ins[vis][i], Ins[vis][i - 1]); 58 } 59 else 60 { 61 if (Dell(vis, num)) continue; 62 Delll(vis); 63 Del[vis].emplace_back(num); 64 for (int len = Del[vis].size(), i = len - 1; i >= 1; --i) if (Del[vis][i] < Del[vis][i - 1]) 65 swap(Del[vis][i], Del[vis][i - 1]); 66 } 67 } 68 } 69 70 inline bool Com() 71 { 72 if (Ins[0].size() != Ins[1].size() || Del[0].size() != Del[1].size()) return false; 73 for (int i = 0, len = Ins[0].size(); i < len; ++i) if (Ins[0][i].first != Ins[1][i].first || Ins[0][i].second != Ins[1][i].second) 74 return false; 75 for (int i = 0, len = Del[0].size(); i < len; ++i) if (Del[0][i] != Del[1][i]) 76 return false; 77 return true; 78 } 79 80 inline void Run() 81 { 82 work(0); work(1); 83 puts(Com() ? "0" : "1"); 84 } 85 86 int main() 87 { 88 #ifdef LOCAL 89 freopen("Test.in", "r", stdin); 90 #endif 91 92 Run(); 93 94 return 0; 95 }
J - Grid Coloring
题意:给出一个n * m 的地图,上面有一些点已经涂色,如果已经涂了B 那么从左上角到这个点的矩形都是B 如果是R 那么从右下角的矩形都是R 有一些空点,求有多少种染色方案
思路:F[i][j][2] 表示 到第i行第j列这个点涂0(‘B’) 或者 涂1('R') 有多少种方案
如果这个点涂0 那么它左边都是已经确定的 转移的状态就是它下面那个点涂0的方案数+涂1的方案数
如果这个点涂1,那么它下面都是已经确定了,转移的状态就是它左边那个点涂0的方案数+涂1的方案数
注意本来就是0和1的情况
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 50 5 #define ll long long 6 7 int n, m; 8 char G[N][N]; 9 ll dp[N][N]; 10 11 inline bool Full(int x, int y, int vis) 12 { 13 if (!vis) 14 { 15 for (int i = 1; i <= x; ++i) 16 for (int j = 1; j <= y; ++j) 17 { 18 if (G[i][j] == 'R') 19 return false; 20 G[i][j] = 'B'; 21 } 22 } 23 else 24 { 25 for (int i = x; i <= n; ++i) 26 for (int j = y; j <= m; ++j) 27 { 28 if (G[i][j] == 'B') 29 return false; 30 G[i][j] = 'R'; 31 } 32 } 33 return true; 34 } 35 36 inline bool work() 37 { 38 for (int i = 1; i <= n; ++i) 39 { 40 for (int j = 1; j <= m; ++j) 41 { 42 if (G[i][j] == 'B') 43 { 44 if (Full(i, j, 0) == false) 45 return false; 46 } 47 else if (G[i][j] == 'R') 48 { 49 if (Full(i, j, 1) == false) 50 return false; 51 } 52 } 53 } 54 return true; 55 } 56 57 inline void Run() 58 { 59 while (scanf("%d%d", &n, &m) != EOF) 60 { 61 for (int i = 1; i <= n; ++i) scanf("%s", G[i] + 1); 62 if (work() == false) 63 { 64 puts("0"); 65 continue; 66 } 67 memset(dp, 0, sizeof dp); 68 for (int i = 1; i <= n; ++i) dp[i][0] = 1; 69 for (int j = 1; j <= m; ++j) dp[n + 1][j] = 1; 70 for (int i = n; i >= 1; --i) 71 { 72 for (int j = 1; j <= m; ++j) 73 { 74 if (G[i][j] == '.') 75 { 76 dp[i][j] = dp[i + 1][j] + dp[i][j - 1]; 77 } 78 else if (G[i][j] == 'B') 79 dp[i][j] = dp[i + 1][j]; 80 else 81 dp[i][j] = dp[i][j - 1]; 82 } 83 } 84 printf("%lld\n", dp[1][m]); 85 } 86 } 87 88 int main() 89 { 90 #ifdef LOCAL 91 freopen("Test.in", "r", stdin); 92 #endif 93 94 Run(); 95 96 return 0; 97 }
K - Spinning Up Palindromes
留坑。
L - Delayed Work
水(暴力枚举人数)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define INF 0x3f3f3f3f 6 #define D 1000000 7 8 double k, p, x; 9 10 int main() 11 { 12 while (scanf("%lf%lf%lf", &k, &p, &x) != EOF) 13 { 14 double ans = INF; 15 for (int i = 1; i <= D; ++i) 16 { 17 double day = (k * 1.0 / i); 18 ans = min(ans, x * i + p * day); 19 } 20 printf("%.3f\n", ans); 21 } 22 return 0; 23 }
M - Unsatisfying
留坑。