A - Wrestling Match
二分图判定。
#include<bits/stdc++.h>
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<vector<int>> g(n + 1) ;
vector<int> 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<int> a(x + 1) ;
vector<int> b(y + 1) ;
for(int i = 1 ; i <= x ; i ++) cin >> a[i] ;
for(int i = 1 ; i <= y ; i ++) cin >> b[i] ;
vector<int> vis(n + 1 , 0) ;
function<bool(int , int)> ok = [&](int u , int c)
{
queue<int> 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
把题目中式子的消除后解一元二次方程即可。
#include<bits/stdc++.h>
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前缀和,结论如下:
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)
#include<bits/stdc++.h>
using namespace std ;
vector<int> 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<int> c(n + 1) ;
for(int i = 1 ; i <= n ; i ++) cin >> c[i] , c[i] -- ;
vector<vector<int>> 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<vector<int>> 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<void(int , int)> 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
表示当前有个黑球和个红球且面对这个局面可以赢的概率。
转移方程:
#include<bits/stdc++.h>
using namespace std ;
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int k ;
while(cin >> k)
{
k ++ ;
vector<double> dp(k + 1 , 0.0) ;
function<double(int)> 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<bits/stdc++.h>
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<int> 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<bits/stdc++.h>
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
留坑。