2021ICPC沈阳 - B E F J
The 2021 ICPC Asia Shenyang Regional Contest
B 图论拆位染色
E 签到
F 字符串
J BFS
B. Bitwise Exclusive-OR Sequence
参考题解
将每一个数字视为图中一个点,对每一个限制建图连边带权
图中可能会出现重边和环,出现重边时,重边权值需相等;出现环时,环上边权异或值应该为 0
再在图上跑 dfs,在链上维护一个前缀异或和,同时统计每一个连通块
最后对每一个连通块考虑每一位怎么放置01使得1的放置次数最少即可
const int N = 1e5 + 5, inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3f, mod = 998244353; int n, m; vector<pii> e[N]; bool vis[N], flag; ll pre[N];// 统计前缀异或 vector<int> to[N]; void dfs(int u, int center){ vis[center] = true; for(auto &[v, w] : e[center]){ if(vis[v]){// 重边或者成环 if((pre[center] ^ w) != pre[v]){ flag = true; return ; } }else{ pre[v] = pre[center] ^ w; to[u].push_back(v); dfs(u, v); } } return ; } ll calc(int u){ int tot = to[u].size(), a = 0; for(int i = 0; i < 30; ++ i){ int cnt = 0; for(auto v : to[u]) if(pre[v] >> i & 1) ++ cnt; if(cnt > tot + 1 - cnt) a |= 1 << i; } ll ans = a; for(auto v : to[u]) ans += pre[v] ^ a; return ans; } void solve(){ cin >> n >> m; while(m --){ int u, v, w; cin >> u >> v >> w; e[u].push_back({v, w}); e[v].push_back({u, w}); } ll ans = 0; for(int i = 1; i <= n; ++ i){ flag = false; if(!vis[i]){ dfs(i, i); if(flag){ cout << -1 << '\n'; return ; } ans += calc(i); } } cout << ans << '\n'; return ; }
30遍 dfs 做法
const int N = 1e5 + 5, M = 30 + 5, inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3f, mod = 998244353; int n, m, sum, vis[N], cnt[M], f[N]; bool flag; vector<pii> e[N]; void dfs(int u, int val){ f[u] = val; ++ sum; vis[u] = true; for(int i = 0; i <= 30; ++ i) if(val >> i & 1) ++ cnt[i]; for(auto & [v, w] : e[u]){ if(vis[v]){ if((val ^ w) != f[v]){ flag = true; return ; } }else dfs(v, val ^ w); } return ; } void solve(){ cin >> n >> m; for(int i = 0; i < m; ++ i){ int u, v, w; cin >> u >> v >> w; e[u].push_back({v, w}); e[v].push_back({u, w}); } ll ans = 0; for(int i = 1; i <= n; ++ i){ if(vis[i]) continue; mem(cnt, 0); sum = 0; flag = false; dfs(i, 0); if(flag){ cout << -1 << '\n'; return ; } for(int i = 0; i <= 30; ++ i){ ans += (ll)min(cnt[i], sum - cnt[i]) * (1 << i);// 注意long long } } cout << ans << '\n'; return ; }
E. Edward Gaming, the Champion
暴力找给定字符串出现的次数
void solve(){ string ss; cin >> ss; int ans = 0; for(int i = 0; i < ss.size(); ++ i) if(ss.substr(i, 5) == "edgnb") ++ ans; cout << ans << '\n'; return ; }
F. Encoded Strings I
从后往前考虑问题,如果某个字母第一次出现,那么接下来出现的相同字母都以它作为最后一个
从后往前统计所有答案取字典序最大的答案即可
void solve(){ string ss, ans = ""; int n; cin >> n >> ss; for(int i = 0; i < n; ++ i){ vector<int> lei(26, -1); int cnt = 0; string t = ""; for(int j = i; j >= 0; -- j){ if(lei[ss[j] - 'a'] == -1){ lei[ss[j] - 'a'] = cnt; t = (char)('a' + cnt) + t; ++ cnt; }else t = (char)('a' + lei[ss[j] - 'a']) + t; } if(t > ans) ans = t; } cout << ans << '\n'; return ; }
J. Luggage Lock
注意到字符串
故我们可以预处理出从字符串 0000 到所有字符串的最小操作次数,利用一个 BFS 即可,之后 O(1) 完成询问
map<string, int> state; void pre(){ string ss; queue<string> p; p.push("0000"); state["0000"] = 0; while(p.size()){ string t = p.front(); p.pop(); for(int i = 0; i < 4; ++ i) for(int j = 0; j < 4; ++ j){ string up = t, down = t; for(int k = i; k <= j; ++ k){ up[k] = (up[k] - '0' + 1) % 10 + '0'; down[k] = (down[k] - '0' + 9) % 10 + '0'; } if(!state.count(up)){ state[up] = state[t] + 1; p.push(up); } if(!state.count(down)){ state[down] = state[t] + 1; p.push(down); } } } return ; } void solve(){ string s, t; cin >> s >> t; for(int i = 0; i < 4; ++ i){ t[i] = (10 + t[i] - s[i]) % 10 + '0'; } cout << state[t] << '\n'; return ; }
本文来自博客园,作者:Qiansui,转载请注明原文链接:https://www.cnblogs.com/Qiansui/p/17836430.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步