博客
关于我
The 2016 ACM-ICPC Asia Dalian Regional Contest 部分题解
阅读量:280 次
发布时间:2019-03-03

本文共 7695 字,大约阅读时间需要 25 分钟。

A - Wrestling Match

二分图判定。

#include
using 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

威佐夫博弈。a_k=\left \lfloor \frac{k*(\sqrt{5}+1)}{2} \right \rfloor,b_k=a_k+k是必败态。

需要上一个java

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

把题目中式子的gcd消除后解一元二次方程即可。

#include
using 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前缀和,结论如下:sum[1:$2^n$] = n*$2^{n-1}$+$2^n$ \ sum[6] = sum[1:2] + sum[1:4]

2.问1-n中有多少个数x满足,[x-lowbit(x)+1,x]这个区间包含了询问的数。手动模拟后可知除了x本身外,从lowbit开始往高的每个0换成1,然后低位换成0的那个数才符合

 

F - Detachment 

打表可以发现最优一定是拆成2、3、4、5、6这样连续的数字,二分找到最大的p满足\sum_{i=2}^pi \leq x,再设q=x-\sum_{i=2}^p i,若q<p,那就让p-q+1~p都+1,若q=p,那就拆成3、4、5...p、p+2。

 

G - Garden of Eden

dp[i][j]表示以i为路径的一个端点,且路径的另一个端点在以i为根的子树内,且路径颜色集合的状压状态是j的路径数。

暴力合并复杂度太高,考虑剪枝。

s|t=2^k-1预处理出满足要求的(s,t)二元组。

又因为dp[i][]不是很满的,只有这个状态方案数大于0再去匹配。

也可以用点分治去冲,不过我感觉复杂度都差不多。

本题可以做到O(32n)的复杂度,要支持插入一个10位的二进制数,询问和一个10位的二进制数或运算=1023的数的数量,现在插入是O(1)的,询问是O(1023)的,如果我们把数字拆成低5位和高5位,可以使插入和询问的复杂度均为O(32)

#include
using 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 

dp[i]表示当前有i个黑球和1个红球且面对这个局面可以赢的概率。

转移方程:dp[i]=\frac{1}{i+1}+\frac{i}{i+1}*(1-dp[i-1])

#include
using 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

温暖的签到题。

#include
using 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

温暖的签到题。

#include
using 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

留坑。

 

转载地址:http://adml.baihongyu.com/

你可能感兴趣的文章
MyBatisPlus快速入门——MyBatisPlus集成Druid配置应用
查看>>
BCGControlBar教程:应用向导
查看>>
MyEclipse教程:Web开发——部署并测试项目
查看>>
【更新】CLion v2018.3发布(六):VCS和插件
查看>>
文件服务器——src文件夹
查看>>
从零构建通讯器--4.4-4.5信号在创建线程的实战作用、write函数写入日志设置成不混乱、文件IO详解
查看>>
从零构建通讯器--5.2三次握手,telnet,wireshark
查看>>
如何判断两个浮点数是否相等?
查看>>
2017ccpc杭州 E. Master of Subgraph(点分治 + 树dp + bitset)
查看>>
2021牛客寒假算法基础集训营3
查看>>
营收环比增幅近50%,星巴克在经历“劫”后重生吗?
查看>>
苹果进军搜索,背后藏着什么“阳谋”?
查看>>
egg:如何在控制器中拿到前端传的参数
查看>>
RPA实施指南:企业如何实现流程优化?
查看>>
干货丨RPA售前六技能
查看>>
MVC之修改
查看>>
使用pycharm链接数据库MySQL
查看>>
Linux基础学习笔记
查看>>
struct 模块
查看>>
python之面向对象编程
查看>>