CCPC-Wannafly Winter Camp Day4 (Div2, onsite)
Replay
Dup4:
- 两轮怎么退火啊?
- 简单树形dp都不会了,送了那么多罚时
- 简单题都不想清楚就乱写了,喵喵喵?
X:
- 欧拉怎么回路啊, 不会啊。
- 还是有没有手误?未思考清楚或者未检查就提交, 导致自己白送罚时。
A:夺宝奇兵
Solved.
考虑$所有i >= 2 需要跟i - 1 连两条边 只有两种可能 取最小的一种$
$注意n的两个点要连一条边$
![](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 const int maxn = 1e5 + 10; 8 9 struct node{ 10 int x1, x2, y1, y2; 11 }arr[maxn]; 12 13 ll calc(int i,int j) 14 { 15 ll ans1 = abs(arr[i].x1 - arr[j].x1) + abs(arr[i].y1 - arr[j].y1) + abs(arr[i].x2 - arr[j].x2) + abs(arr[i].y2 - arr[j].y2); 16 ll ans2 = abs(arr[i].x1 - arr[j].x2) + abs(arr[i].y1 - arr[j].y2) + abs(arr[i].x2 - arr[j].x1) + abs(arr[i].y2 - arr[j].y1); 17 return min(ans1, ans2); 18 } 19 20 int n , m; 21 22 int main() 23 { 24 while(~scanf("%d %d", &n, &m)) 25 { 26 for(int i = 1; i <= n; ++i) scanf("%d %d %d %d", &arr[i].x1, &arr[i].y1, &arr[i].x2, &arr[i].y2); 27 ll ans = 0; 28 for(int i = 2; i <= n; ++i) ans += calc(i, i - 1); 29 ans += abs(arr[n].x1 - arr[n].x2) + abs(arr[n].y1 - arr[n].y2); 30 printf("%lld\n", ans); 31 } 32 return 0; 33 }
C:最小边覆盖
Solved.
考虑$No的情况$
- 存在一个点的度数为0(没有被覆盖)
- 存在一条边所连接的两个点其度数 >= 2 即这条边去掉还是个最小边覆盖
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 300010 5 #define pii pair <int, int> 6 int n, m; 7 pii G[N]; 8 int d[N]; 9 10 bool f() 11 { 12 for (int i = 1; i <= n; ++i) if (!d[i]) return false; 13 for (int i = 1; i <= m; ++i) 14 { 15 int u = G[i].first, v = G[i].second; 16 if (d[u] >= 2 && d[v] >= 2) 17 return false; 18 } 19 return true; 20 } 21 22 int main() 23 { 24 while (scanf("%d%d", &n, &m) != EOF) 25 { 26 memset(d, 0, sizeof d); 27 for (int i = 1, u, v; i <= m; ++i) 28 { 29 scanf("%d%d", &u, &v); 30 ++d[u], ++d[v]; 31 G[i] = pii(u, v); 32 } 33 puts(f() ? "Yes" : "No"); 34 } 35 return 0; 36 }
F:小小马
Solved.
因为不同颜色出现次数相同, 所以步数一定是奇数。
暴力跑出大数据的状态, 发现颜色相同就输出No, 否则输出Yes。
小数据暴力跑即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e6 + 10; 6 7 struct node{ 8 int x, y; 9 int step; 10 node(){} 11 node(int x, int y, int step): x(x), y(y), step(step){} 12 }; 13 14 int n, m; 15 int sx, sy, ex, ey; 16 int vis[11][maxn][2]; 17 int dir[8][2] = {-2, -1, -2, 1, -1, -2, -1, 2, 1, -2, 1, 2, 2, -1, 2, 1}; 18 19 int judge(int x, int y,int step) 20 { 21 if(x < 1 || x > n || y < 1 || y > m || vis[x][y][step % 2]) return false; 22 else return true; 23 } 24 25 void BFS() 26 { 27 memset(vis, 0, sizeof vis); 28 queue<node>q; 29 q.push(node(sx, sy, 0)); 30 while(!q.empty()) 31 { 32 node st = q.front(); 33 q.pop(); 34 node now = st; 35 now.step++; 36 for(int i = 0; i < 8; ++i) 37 { 38 now.x = st.x + dir[i][0]; 39 now.y = st.y + dir[i][1]; 40 if(judge(now.x, now.y, now.step)) 41 { 42 vis[now.x][now.y][now.step % 2] = 1; 43 q.push(now); 44 } 45 } 46 } 47 } 48 49 int main() 50 { 51 while(~scanf("%d %d", &n, &m)) 52 { 53 scanf("%d %d", &sx, &sy); 54 scanf("%d %d", &ex, &ey); 55 if(n < 10 || m < 10) 56 { 57 if(n > m) 58 { 59 swap(n, m); 60 swap(sx, sy); 61 swap(ex, ey); 62 } 63 BFS(); 64 if(vis[ex][ey][1]) puts("Yes"); 65 else puts("No"); 66 } 67 else 68 { 69 int ans1 = (sx + sy) % 2; 70 int ans2 = (ex + ey) % 2; 71 if(ans1 != ans2) puts("Yes"); 72 else puts("No"); 73 } 74 } 75 return 0; 76 }
G:置置置换
Solved.
$在已知1-n的方案数, 枚举n+1出现的位置$
$当枚举到位置x的时候, 选出x-1个数放在前x个, 然后计算方案数 统计即可$
$2 \cdot ans_{n + 1} = \sum\limits_{i = 0}^{n} C_n^i \cdot ans_i \cdot ans_{n - 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 const ll MOD = (ll)1e9 + 7; 8 const int maxn = 1e3 + 10; 9 10 int n; 11 ll fac[maxn]; 12 ll inv[maxn]; 13 ll invfac[maxn]; 14 15 ll ans[maxn]; 16 17 void Init() 18 { 19 fac[1] = 1, inv[1] = 1, invfac[1] = 1; 20 for(int i = 2; i < maxn; ++i) 21 { 22 fac[i] = fac[i - 1] * i % MOD; 23 inv[i] = inv[MOD % i] * (MOD - MOD / i) % MOD; 24 invfac[i] = invfac[i - 1] * inv[i] % MOD; 25 } 26 } 27 28 ll calc(int n, int m) 29 { 30 if(n == m || m == 0) return 1ll; 31 return fac[n] * invfac[m] % MOD * invfac[n - m] % MOD; 32 } 33 34 35 int main() 36 { 37 Init(); 38 ans[0] = ans[1] = 1; 39 for(int i = 1; i + 1 < maxn; ++i) 40 { 41 for(int j = 0; j <= i; ++j) 42 { 43 ans[i + 1] = (ans[i + 1] + calc(i, j) * ans[j] % MOD * ans[i - j] % MOD) % MOD; 44 } 45 ans[i + 1] = (ans[i + 1] * inv[2]) % MOD; 46 } 47 while (scanf("%d", &n) != EOF) 48 { 49 printf("%lld\n", ans[n]); 50 } 51 return 0; 52 }
I:咆咆咆哮
Solved.
考虑如果选择$a_i的个数固定为x,那么对于所有选取b_i的卡牌来说它的贡献是固定的$
枚举$x, 再贪心选取即可$
![](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 1010 6 int n, a[N], b[N]; 7 8 ll f(int x) 9 { 10 priority_queue <ll> pq; 11 ll res = 0; 12 for (int i = 1; i <= n; ++i) 13 { 14 res += a[i]; 15 pq.push(1ll * b[i] * x - a[i]); 16 } 17 for (int i = 1; i <= n - x; ++i) 18 { 19 res += pq.top(); 20 pq.pop(); 21 } 22 return res; 23 } 24 25 int main() 26 { 27 while (scanf("%d", &n) != EOF) 28 { 29 for (int i = 1; i <= n; ++i) scanf("%d%d", a + i, b + i); 30 ll res = 0; 31 for (int i = 1; i <= n; ++i) 32 res = max(res, f(i)); 33 printf("%lld\n", res); 34 } 35 return 0; 36 }
Div1:
三分
好像满足凸性? 我不会证啊。..
![](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 int n, a[N], b[N]; 7 8 ll check(int x) 9 { 10 ll res = 0; 11 priority_queue <ll> pq; 12 for (int i = 1; i <= n; ++i) 13 { 14 res = res + a[i]; 15 pq.push(1ll * b[i] * x - a[i]); 16 } 17 for (int i = n - x; !pq.empty() && i; --i) 18 { 19 res += pq.top(); pq.pop(); 20 } 21 return res; 22 } 23 24 int main() 25 { 26 while (scanf("%d", &n) != EOF) 27 { 28 for (int i = 1; i <= n; ++i) scanf("%d%d", a + i, b + i); 29 int l = 0, r = n; ll res = 0; 30 while (r - l >= 0) 31 { 32 int midl = (l + r) >> 1; 33 int midr = (midl + r) >> 1; 34 ll tmpl = check(midl); 35 ll tmpr = check(midr); 36 if (tmpl <= tmpr) 37 { 38 res = max(res, tmpr); 39 l = midl + 1; 40 } 41 else 42 { 43 res = max(res, tmpl); 44 r = midr - 1; 45 } 46 } 47 printf("%lld\n", res); 48 } 49 return 0; 50 }
K:两条路径
Solved.
考虑$x作为交它的权值要被算上$
在考虑两条路径可以选取端点,端点的选择在其儿子对应的子树中选取一个点且仅能选取一个
树形DP即可
![](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 INFLL 0x3f3f3f3f3f3f3f3f 7 int n, q; 8 ll val[N]; 9 vector <int> G[N]; 10 ll Bit[35], f[N]; 11 12 void DFS(int u, int fa) 13 { 14 f[u] = -INFLL; 15 for (auto v : G[u]) if (v != fa) 16 { 17 DFS(v, u); 18 f[u] = max(f[u], f[v]); 19 } 20 f[u] = max(f[u], 0ll); 21 f[u] += val[u]; 22 } 23 24 void out(ll x) 25 { 26 if (x < 0) putchar('-'), x = -x; 27 string res = ""; 28 while (x) 29 { 30 res += (x % 2 + '0'); 31 x /= 2; 32 } 33 reverse(res.begin(), res.end()); 34 cout << res << "\n"; 35 } 36 37 int main() 38 { 39 Bit[0] = 1; 40 for (int i = 1; i <= 30; ++i) Bit[i] = Bit[i - 1] << 1; 41 while (scanf("%d", &n) != EOF) 42 { 43 for (int i = 1; i <= n; ++i) G[i].clear(); 44 for (int i = 1, x; i <= n; ++i) 45 { 46 scanf("%d", &x); 47 if (!x) 48 { 49 val[i] = 0; 50 continue; 51 } 52 int vis = 1; 53 if (x < 0) 54 { 55 x = -x; 56 vis = -1; 57 } 58 --x; 59 val[i] = Bit[x] * vis; 60 } 61 for (int i = 1, u, v; i < n; ++i) 62 { 63 scanf("%d%d", &u, &v); 64 G[u].push_back(v); 65 G[v].push_back(u); 66 } 67 int x; 68 scanf("%d", &q); 69 while (q--) 70 { 71 scanf("%d", &x); 72 priority_queue <ll> pq; 73 for (auto v : G[x]) 74 { 75 DFS(v, x); 76 pq.push(f[v]); 77 } 78 ll res = val[x]; 79 for (int i = 1; i <= 4 && !pq.empty() && pq.top() > 0; ++i) 80 { 81 res += pq.top(); pq.pop(); 82 } 83 //cout << res << endl; 84 out(res); 85 } 86 } 87 return 0; 88 }