CCPC-Wannafly Summer Camp 2019 全记录
Posted izcat
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CCPC-Wannafly Summer Camp 2019 全记录相关的知识,希望对你有一定的参考价值。
// 7.19-7.29 东北大学秦皇岛校区十天训练营,题目都挂在了Vjudge上。训练期间比较忙,没空更博总结,回来继续补题消化。
// https://vjudge.net/contest/312902
https://vjudge.net/contest/313217
https://vjudge.net/contest/313584
https://vjudge.net/contest/314412
https://vjudge.net/contest/314730
https://vjudge.net/contest/314974
Day1
这天授课主题是简单图论,节奏挺好,wls两小时理完图论里的基本知识点。
下午的赛题就偏入门了(简单图论无疑),只涉及到最短路问题和简单的搜索以及一些奇怪的技巧。(差分约束呢?最小生成树呢?强连通分量呢?)
A - Jzzhu and Cities (补)
把火车线路加上跑Dijkstra就好了,标记火车线路,相等时也要push。在最短路上的火车线路不能被取消,剩下的全部能取消。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; typedef long long ll; const int maxn = 200010; struct Edge int to; bool istrain; ll w; Edge(int v, bool is, ll ww):to(v), istrain(is), w(ww) bool operator<(const Edge& a)const if(w==a.w) return istrain; // 非火车节点先更新 return w > a.w; ; vector<Edge> G[maxn]; bool vis[maxn]; int d[maxn]; int Dijkstra() memset(d, 0x3f, sizeof(d)); memset(vis, 0, sizeof(vis)); d[1] = 0; int res = 0; priority_queue<Edge> q; q.push(Edge(1, 0, 0)); while(!q.empty()) Edge tmp = q.top(); q.pop(); int u = tmp.to; if(vis[u]) continue; vis[u] = 1; // d[u] = tmp.w; if(tmp.istrain) ++res; for(int i=0;i<G[u].size();i++) int v = G[u][i].to; if(!vis[v] && d[v]>=d[u]+G[u][i].w) d[v] = d[u] + G[u][i].w; q.push(Edge(v, G[u][i].istrain, d[v])); return res; int main() int n, m, k; cin>>n>>m>>k; int u, v, w; for(int i=0;i<m;i++) scanf("%d %d %d", &u, &v, &w); G[u].push_back(Edge(v, 0, w)); G[v].push_back(Edge(u, 0, w)); for(int i=0;i<k;i++) scanf("%d %d", &v, &w); G[1].push_back(Edge(v, 1, w)); // G[v].push_back(Edge(1, 1, w)); printf("%d\\n", k-Dijkstra()); return 0;
BFS 注意打标记!!!(虽然只是3*100的地图也要爆内存!)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; int n, k, sx; char mp[3][110]; bool vis[3][110]; struct node int x, y; node(int _x, int _y):x(_x), y(_y) ; bool check(int x, int y) if(x<0 || x>2) return false; if(y>=n) return true; if(mp[x][y]==‘.‘) return true; return false; bool bfs() queue<node> q; q.push(node(sx, 0)); while(q.size()) node now = q.front(); q.pop(); if(now.y>=n) return true; // printf("(%d,%d) -> ", now.x, now.y); int nx = now.x, ny = now.y+1; if(!check(nx, ny)) continue; // 向右走一步 for(int i=-1;i<=1;i++) // 尝试三个方向移动 nx = now.x + i; if(check(nx, ny) && check(nx, ny+1) && check(nx, ny+2) && !vis[nx][ny+2]) q.push(node(nx, ny+2)); vis[nx][ny+2] = 1; return false; int main() int t; cin>>t; while(t--) scanf("%d %d", &n, &k); getchar(); memset(vis, 0, sizeof(vis)); for(int i=0;i<3;i++) scanf("%s", mp[i]); if(mp[i][0]==‘s‘) sx = i; printf("%s\\n", bfs()?"YES":"NO"); return 0;
C - A Mist of Florescence (补)
构造题,技巧就是设计井字形的连通块,把其他颜色块涂到井字的格子上。
#include<iostream> #include<cstdio> using namespace std; int a, b, c, d; char ans[50][50]; void solve() for(int i=1;i<=12;i++) for(int j=1;j<50;j++) if(i%2==1 && j%2==1 && a) ans[i][j] = ‘A‘, --a; else ans[i][j] = ‘D‘; for(int i=13;i<=24;i++) for(int j=1;j<50;j++) if(i%2==1 && j%2==1 && b) ans[i][j] = ‘B‘, --b; else ans[i][j] = ‘D‘; --c; --d; for(int i=25;i<=36;i++) for(int j=1;j<50;j++) if(i%2==1 && j%2==1 && c) ans[i][j] = ‘C‘, --c; else ans[i][j] = ‘D‘; for(int j=1;j<50;j++) ans[37][j] = ‘C‘; for(int i=38;i<50;i++) for(int j=1;j<50;j++) if(i%2==1 && j%2==1 && d) ans[i][j] = ‘D‘, --d; else ans[i][j] = ‘C‘; int main() cin>>a>>b>>c>>d; solve(); printf("49 49\\n"); for(int i=1;i<50;i++) for(int j=1;j<50;j++) printf("%c", ans[i][j]); printf("\\n"); return 0;
DFS到墙的边界 对每块编号!
#include<iostream> #include<cstdio> using namespace std; int n, m, k; char mp[1010][1010]; int v[1010][1010], id; // v[i][j]: mp[i][j]的分类编号 id: 当前编号 int res[1010*1010]; // res[id]: 第id块的答案 const int dx[] = 0, 0, 1, -1; const int dy[] = 1, -1, 0, 0; int ans; void dfs(int x, int y) if(mp[x][y]==‘*‘) ans++; return; v[x][y] = id; for(int i=0;i<4;i++) int nx = x+dx[i], ny = y+dy[i]; if(nx>=0 && nx<m && ny>=0 && ny<n && !v[nx][ny]) dfs(nx, ny); int main() scanf("%d %d %d", &m, &n, &k); getchar(); for(int i=0;i<m;i++) scanf("%s", mp[i]); for(int i=0;i<m;i++) for(int j=0;j<n;j++) if(mp[i][j]==‘.‘ && !v[i][j]) ++id; ans = 0; dfs(i, j); res[id] = ans; while(k--) int x, y; scanf("%d %d", &x, &y); printf("%d\\n", res[v[x-1][y-1]]); return 0;
F - The Cild and Toy (补)
贪心!由于每去掉一个点,等价于去掉了所有与它相连的边,就是问去掉全部边的最小代价。答案当然就是每条边两个节点权值小的那头的总和。都不用建图!!
#include<iostream> #include<cstdio> using namespace std; const int maxn = 1010; int n, m; int w[maxn]; int main() cin>>n>>m; for(int i=1;i<=n;i++) scanf("%d", &w[i]); int u, v, ans = 0; for(int i=0;i<m;i++) scanf("%d %d", &u, &v); ans += min(w[u], w[v]); printf("%d\\n", ans); return 0;
对连通部分排序就完事了
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; int n, num[310], id; int mp[310][310]; bool vis[310]; int ans[310]; struct list vector<int> num; vector<int> id; L[310]; void dfs(int x, int id) vis[x] = 1; L[id].num.push_back(num[x]); L[id].id.push_back(x); for(int i=1;i<=n;i++) if(mp[x][i]) if(!vis[i]) dfs(i, id); int main() cin>>n; for(int i=1;i<=n;i++) scanf("%d", &num[i]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%1d", &mp[i][j]); for(int i=1;i<=n;i++) if(!vis[i]) dfs(i, ++id); for(int i=1;i<=id;i++) // for(int j=0;j<L[i].num.size();j++) // printf("%d:%d ", L[i].num[j], L[i].id[j]); // // cout<<endl; sort(L[i].num.begin(), L[i].num.end()); sort(L[i].id.begin(), L[i].id.end()); for(int j=0;j<L[i].num.size();j++) ans[L[i].id[j]] = L[i].num[j]; for(int i=1;i<=n;i++) printf("%d%c", ans[i], i!=n?‘ ‘:‘\\n‘); return 0;
H - Alyona and the Tree (补)
从根开始dfs就好,每个节点为max(0LL, now+w[i])
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> using namespace std; const int maxn = 100010; typedef long long ll; struct Edge int to; ll w; Edge(int v, ll ww):to(v), w(ww) ; vector<Edge> G[maxn]; int n, vw[maxn]; int ans; void dfs(int u, int fa, ll now) for(int i=0;i<G[u].size();i++) int v = G[u][i].to; if(v!=fa) if(vw[v]>=now+G[u][i].w) --ans; // printf("%d->%d\\n", u, v); dfs(v, u, max(now+G[u][i].w, 0LL)); int main() cin>>n; ans = n; for(int i=1;i<=n;i++) scanf("%d", &vw[i]); int u, w; for(int i=2;i<=n;i++) scanf("%d %d", &u, &w); G[i].push_back(Edge(u, w)); G[u].push_back(Edge(i, w)); dfs(1, -1, 0); printf("%d\\n", ans-1); return 0;
L - Love Triangle
假的三元环??
#include <iostream> #include <cstdio> #include <algorithm> #include <vector> using namespace std; const int maxn = 5010; int n, tot; int love[maxn], low[maxn]; bool vis[maxn]; bool ans; void dfs(int u) if(ans) return; vis[u] = true; low[u] = ++tot; int v = love[u]; if(v && !vis[v]) dfs(v); if(love[v] && low[love[v]]==low[u]+2 && love[love[v]]==u) ans = true; return; int main() cin>>n; for(int i=1;i<=n;i++) scanf("%d", &love[i]); ans = false; for(int i=1;i<=n;i++) if(!vis[i] && !ans) dfs(i); printf("%s\\n", ans?"YES":"NO"); return 0;
并查集
#include <iostream> #include <cstdio> using namespace std; const int maxn = 500100; int n, m; int fa[maxn]; int g[maxn], cnt[maxn]; int Find(int x) return fa[x]==x?x:(fa[x]=Find(fa[x])); void Union(int x, int y) int a = Find(x); int b = Find(y); if(a==b) return; fa[a] = b; int main() cin>>n>>m; for(int i=1;i<=n;i++) fa[i] = i; while(m--) int k; scanf("%d", &k); for(int i=0;i<k;i++) scanf("%d", &g[i]); for(int i=1;i<k;i++) Union(g[0], g[i]); for(int i=1;i<=n;i++) cnt[Find(i)]++; for(int i=1;i<=n;i++) printf("%d%c", cnt[Find(i)], i!=n?‘ ‘:‘\\n‘); return 0;
O - NP-Hard Problem (补)
二分图裸题。。。
#include<iostream> #include<cstdio> #include<vector> using namespace std; typedef long long ll; const int maxn = 100010; int n, m; vector<int> G[maxn]; int deg[maxn]; int id[maxn]; vector<int> ans[2]; bool dfs(int u) for(int i=0;i<G[u].size();i++) int v = G[u][i]; if(!id[v]) id[v] = 3 - id[u]; if(id[v]==1) ans[0].push_back(v); else ans[1].push_back(v); if(!dfs(v)) return false; else if(id[v]==id[u]) return false; return true; int main() cin>>n>>m; int u, v; for(int i=0;i<m;i++) scanf("%d %d", &u, &v); G[u].push_back(v); G[v].push_back(u); ++deg[u]; for(int i=1;i<=n;i++) if(!deg[i]) continue; if(!id[i]) id[i] = 1; ans[0].push_back(i); if(!dfs(i)) return 0 * printf("-1\\n"); for(int k=0;k<=1;k++) printf("%d\\n", ans[k].size()); for(int i=0;i<ans[k].size();i++) printf("%d%c", ans[k][i], i==ans[k].size()-1?‘\\n‘:‘ ‘); return 0;
Day2
Day3
Day4
Day5
Day6
以上是关于CCPC-Wannafly Summer Camp 2019 全记录的主要内容,如果未能解决你的问题,请参考以下文章
Petrozavodsk Summer Training Camp 2017
BZOJ4896 [Thu Summer Camp2016]补退选
bzoj:4105: [Thu Summer Camp 2015]平方运算