
The 2016 ACM-ICPC Asia Dalian Regional Contest 部分题解
发布日期:2021-05-06 15:23:54
浏览次数:10
分类:技术文章
本文共 7695 字,大约阅读时间需要 25 分钟。
A - Wrestling Match
二分图判定。
#includeusing namespace std ;int main(){ std::ios::sync_with_stdio(false) , cin.tie(0) ; int n , m , x , y ; while(cin >> n >> m >> x >> y) { vector > g(n + 1) ; vector can(n + 1 , false) ; while(m --) { int u , v ; cin >> u >> v ; g[u].push_back(v) ; g[v].push_back(u) ; can[u] = true ; can[v] = true ; } vector a(x + 1) ; vector b(y + 1) ; for(int i = 1 ; i <= x ; i ++) cin >> a[i] ; for(int i = 1 ; i <= y ; i ++) cin >> b[i] ; vector vis(n + 1 , 0) ; function ok = [&](int u , int c) { queue q ; vis[u] = c ; q.push(u) ; while(!q.empty()) { int now = q.front() ; q.pop() ; for(auto v : g[now]) { //cout << "??? " << v << '\n' ; if(vis[v] == 0) { vis[v] = 3 - vis[now] ; q.push(v) ; } else { if(vis[v] != 3 - vis[now]) { //cout << "^^^ " << u << ' ' << v << '\n' ; return false ; } } } } return true ; } ; bool flag = true ; for(int i = 1 ; i <= x ; i ++) if(vis[a[i]] == 0) flag &= ok(a[i] , 1) ; for(int i = 1 ; i <= y ; i ++) if(vis[b[i]] == 0) flag &= ok(b[i] , 2) ; for(int i = 1 ; i <= x ; i ++) if(vis[a[i]] != 1) flag = false ; for(int i = 1 ; i <= y ; i ++) if(vis[b[i]] != 2) flag = false ; for(int i = 1 ; i <= n ; i ++) if(vis[i] == 0 && can[i]) flag &= ok(i , 1) ; //for(int i = 1 ; i <= n ; i ++) cout << i << ' ' << vis[i] << '\n' ; for(int i = 1 ; i <= n ; i ++) if(vis[i] == 0) flag = false ; if(flag) cout << "YES\n" ; else cout << "NO\n" ; } return 0 ;}
B - Regular Number
可选字符匹配问题,shift_and算法模板题
C - Game of Taking Stones
威佐夫博弈。是必败态。
需要上一个
import java.math.BigDecimal ;import java.math.BigInteger ;import java.util.Scanner ;public class Main{ public static void main(String[] args) { Scanner cin = new Scanner(System.in) ; BigDecimal l = BigDecimal.valueOf(2) ; BigDecimal r = BigDecimal.valueOf(3) ; for(int i = 0 ; i < 500 ; i ++) { BigDecimal mid = l.add(r).divide(BigDecimal.valueOf(2)) ; if(mid.multiply(mid).compareTo(BigDecimal.valueOf(5)) < 0) l = mid ; else r = mid ; } while(cin.hasNext()) { BigDecimal a = cin.nextBigDecimal() ; BigDecimal b = cin.nextBigDecimal() ; int x = a.compareTo(b) ; if(x > 0) { BigDecimal c = a ; a = b ; b = c ; } BigDecimal k = b.subtract(a) ; BigDecimal ans = l.add(BigDecimal.valueOf(1)).multiply(k).divide(BigDecimal.valueOf(2)) ; ans = ans.setScale(0 , BigDecimal.ROUND_FLOOR) ; if(ans.add(k).compareTo(b) == 0) System.out.println("0") ; else System.out.println("1") ; } }}
D - A Simple Math Problem
把题目中式子的消除后解一元二次方程即可。
#includeusing namespace std ;#define ll long long ll sq(ll x){ ll t = sqrt(x) ; for(ll i = t - 1 ; i <= t + 1 ; i ++) if(i * i == x) return i ; return 0 ;}int main(){ std::ios::sync_with_stdio(false) , cin.tie(0) ; ll a , b ; while(cin >> a >> b) { ll d = __gcd(a , b) ; b *= d ; //cout << "^^^ " << a * a << ' ' << 4 * b << '\n' ; if(a * a == 4 * b) { //if(a % 2 == 0) cout << "ok\n" ; if(a % 2 == 0) cout << a / 2 << ' ' << a / 2 << '\n' ; else cout << "No Solution\n" ; } else if(a * a >= 4 * b) { ll tmp = sq(a * a - 4 * b) ; //cout << "??? " << tmp << '\n' ; if(tmp == 0) cout << "No Solution\n" ; else { if((a + tmp) % 2 == 0 && (a - tmp) % 2 == 0) cout << (a - tmp) / 2 << ' ' << (a + tmp) / 2 << '\n' ; else cout << "No Solution\n" ; } } else cout << "No Solution\n" ; } return 0 ;}
E - Aninteresting game
本题有两种询问
1.本质就是lowbit前缀和,结论如下:
2.问1-n中有多少个数x满足,[x-lowbit(x)+1,x]这个区间包含了询问的数。手动模拟后可知除了x本身外,从lowbit开始往高的每个0换成1,然后低位换成0的那个数才符合
F - Detachment
打表可以发现最优一定是拆成2、3、4、5、6这样连续的数字,二分找到最大的p满足,再设
,若q<p,那就让p-q+1~p都+1,若q=p,那就拆成3、4、5...p、p+2。
G - Garden of Eden
表示以
为路径的一个端点,且路径的另一个端点在以
为根的子树内,且路径颜色集合的状压状态是
的路径数。
暴力合并复杂度太高,考虑剪枝。
预处理出满足要求的
二元组。
又因为不是很满的,只有这个状态方案数大于0再去匹配。
也可以用点分治去冲,不过我感觉复杂度都差不多。
本题可以做到O(32n)的复杂度,要支持插入一个10位的二进制数,询问和一个10位的二进制数或运算=1023的数的数量,现在插入是O(1)的,询问是O(1023)的,如果我们把数字拆成低5位和高5位,可以使插入和询问的复杂度均为O(32)
#includeusing namespace std ;vector h[12][1025] ;int main(){ std::ios::sync_with_stdio(false) , cin.tie(0) ; int n , k ; for(int p = 1 ; p <= 10 ; p ++) for(int i = 0 ; i < (1 << p) ; i ++) for(int j = 0 ; j < (1 << p) ; j ++) if((i | j) == (1 << p) - 1) h[p][i].push_back(j) ; while(cin >> n >> k) { vector c(n + 1) ; for(int i = 1 ; i <= n ; i ++) cin >> c[i] , c[i] -- ; vector > g(n + 1) ; for(int i = 1 ; i <= n - 1 ; i ++) { int u , v ; cin >> u >> v ; g[u].push_back(v) ; g[v].push_back(u) ; } if(k == 1) { cout << 1ll * n * n << '\n' ; continue ; } vector > dp(n + 1) ; for(int i = 0 ; i <= n ; i ++) dp[i].resize((1 << k) , 0) ; long long ans = 0 ; int up = (1 << k) ; function dfs = [&](int fa , int u) { dp[u][(1 << c[u])] = 1 ; for(auto v : g[u]) { if(v == fa) continue ; dfs(u , v) ; for(int i = 0 ; i < up ; i ++) { if(dp[v][i] == 0) continue ; for(auto t : h[k][i]) { //cout << u << ' ' << t << ' ' << dp[u][t] << '\n' ; //cout << v << ' ' << i << ' ' << dp[v][i] << '\n' ; ans += 1ll * dp[u][t] * dp[v][i] ; } } for(int i = 0 ; i < up ; i ++) { int col = (i | (1 << c[u])) ; dp[u][col] += dp[v][i] ; } } } ; dfs(1 , 1) ; //cout << ans << '\n' ; //for(int i = 1 ; i <= n ; i ++) ans += dp[i][(1 << k) - 1] ; cout << ans * 2 << '\n' ; } return 0 ;}
H - To begin or not to begin
表示当前有
个黑球和
个红球且面对这个局面可以赢的概率。
转移方程:
#includeusing namespace std ;int main(){ std::ios::sync_with_stdio(false) , cin.tie(0) ; int k ; while(cin >> k) { k ++ ; vector dp(k + 1 , 0.0) ; function dfs = [&](int i) { if(i == 1) { dp[i] = 1.0 ; return dp[i] ; } dp[i] = 1.0 / i + 1.0 * (i - 1) / i * (1.0 - dfs(i - 1)) ; return dp[i] ; } ; dfs(k) ; if(fabs(dp[k] - 0.5) < 1e-6) cout << "0\n" ; else if(dp[k] > 0.5) cout << "1\n" ; else cout << "2\n" ; } return 0 ;}
I - Convex
温暖的签到题。
#includeusing namespace std ;const double pi = acos(-1.0) ;int main(){ std::ios::sync_with_stdio(false) , cin.tie(0) ; int n , d ; while(cin >> n >> d) { vector a(n) ; for(int i = 0 ; i < n ; i ++) cin >> a[i] ; double ans = 0 ; for(int i = 0 ; i < n ; i ++) ans += 0.5 * d * d * sin(a[i] / 180.0 * pi) ; cout << fixed << setprecision(3) << ans << '\n' ; } return 0 ;}
J - Find Small A
温暖的签到题。
#includeusing namespace std ;int main(){ std::ios::sync_with_stdio(false) , cin.tie(0) ; int n ; while(cin >> n) { int ans = 0 ; while(n --) { unsigned x ; cin >> x ; while(x > 0) { if(x % 256 == 97) ans ++ ; x /= 256 ; } } cout << ans << '\n' ; } return 0 ;}
K - Guess the number
留坑。
发表评论
最新留言
第一次来,支持一个
[***.219.124.196]2025年04月05日 14时48分58秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
钉钉IP及域名列表
2019-03-03
CENTOS 删除nginx
2019-03-03
【redis键过期删除策略】很高兴再次认识你
2019-03-03
【工具篇】EasyExcel的应用
2019-03-03
SSM发送手机验证码——以网建SMS为例
2019-03-03
大范围卫星影像快速处理
2019-03-03
监控264后缀文件播放
2019-03-03
Java并发编程笔记-思维导图
2019-03-03
网站在线偷拍照片源码
2019-03-03
养猫最新版小程序源码
2019-03-03
Thinkphp6.0+vue个人虚拟物品发卡网站源码
2019-03-03
手游服务端框架之关于玩家数据的解决方案
2019-03-03
游戏服务端框架之网关
2019-03-03
游戏服务端框架之模仿SpringMvc实现消息路由
2019-03-03
动态摇动吊牌自适应网站404页面源码
2019-03-03
炫酷文字消失动画网站404页面源码
2019-03-03
EMLOG模板山河网站主题分享
2019-03-03
2020年,51Talk求一个盈利的机会
2019-03-03
2019数字音乐市场年度回顾,QQ音乐全面领先
2019-03-03
迅雷新财报背后:下载一哥到艰难求生
2019-03-03