博客
关于我
The 2016 ACM-ICPC Asia Dalian Regional Contest 部分题解
阅读量:282 次
发布时间: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/

你可能感兴趣的文章
平均分392分!某985计算机专硕复试线暴涨!
查看>>
为何二战考生成功率远远大于应届?
查看>>
计算机专业【本科生】毕业还不如【专科生】?
查看>>
考研408联盟新添一所985!某知名大学专业课改用408!
查看>>
最有钱的大学是哪个?教育部直属高校公布2018年决算
查看>>
408的逆袭!武汉大学所有计算机/软件专业都改为408!
查看>>
408又多一所学校!广东某大学专业课改为408!
查看>>
【报名问题】考研现场确认时发现报考点选错了怎么办?
查看>>
100000+人体验过后都说:这TM绝对是最变态的英语学习方法……
查看>>
广东省将新增一所“中科大”,办学规模初定1万人!
查看>>
提醒 | 未下载打印准考证的考生,不能参加2020年考研初试
查看>>
【调剂】2020年中科院上海光机所接收报考硕士研究生调剂生的通知
查看>>
【调剂】其它计算机/软件调剂信息 20.4.21
查看>>
【调剂】211 内蒙古大学计算机学院2020年拟接收调剂硕士研究生公告
查看>>
【调剂】浙江理工大学2020年硕士研究生调剂信息
查看>>
【调剂】华侨大学媒体分析与数据挖掘小组招收学硕调剂生
查看>>
分数线385!平均分399!985大学计算机的真正“实力”!
查看>>
【调剂】211云南大学2020年硕士研究生招生调剂通知
查看>>
【调剂】985复旦大学类脑智能科学与技术研究院硕士研究生招生接收校内调剂考生工作细则...
查看>>
【调剂】沈阳航空航天大学2020年硕士研究生调剂信息
查看>>