2020杭電多校#7(補)
阿新 • • 發佈:2020-09-03
1007 Game
題意
在二維圖上有n個點,從第一個點開始,然後兩個人依次選點,假設先手選的A且\(|OA|=d\),則後手選B點的時候必須滿足\(|AB|>d\)。直到有一個人不能選擇新的點為止,問先手能不能贏。
思路
暴力將每兩個點之間的距離以及這兩個點存起來,倒敘遍歷距離,距離相等的可以看成一個層次。當第一個點所在的層次不止有一個點時,先手的最優策略為在第一個點的同層次選點,後手只能跨層次,而由於一個層次最少有兩個點,因此先手可以繼續選擇而必勝。
程式碼
#include <bits/stdc++.h> #define ll long long #define pll pair<ll, ll> using namespace std; const int maxn = 1e5 + 7; const int mod = 1e9 + 7; int T, n, vis[maxn]; pll a[maxn]; struct node { int a, b; ll dis; }; ll dis(pll a, pll b) { return (a.first - b.first) * (a.first - b.first) + (a.second - b.second) * (a.second - b.second); } bool cmp(node a, node b) { return a.dis > b.dis; } int main() { ios::sync_with_stdio(false); cin.tie(0); freopen("data.in", "r", stdin); //freopen("data.out", "w", stdout); cin >> T; while(T--) { cin >> n; memset(vis, 0, sizeof(vis)); for(int i = 0; i < n; i++) { cin >> a[i].first >> a[i].second; } vector<node> vec; for(int i = 0; i < n; i++) { for(int j = i + 1; j < n; j++) { vec.push_back(node{i, j, dis(a[i], a[j])}); } } sort(vec.begin(), vec.end(), cmp); string ans = "NO"; for(auto item: vec) { if(vis[item.a] || vis[item.b]) continue; vis[item.a] = vis[item.b] = 1; if(item.a == 0 || item.b == 0) ans = "YES"; } cout << ans << endl; } return 0; }
1009 Increasing and Decreasing
題意
問能否構造出一個長度為n,最長上升子序列長度為x,下降子序列長度為y的排列。
思路
可以考慮構造類似321 654 987....這樣的序列下降長度就是最大的塊的長度,上升長度就是塊的數量。考慮極端情況,要滿足題意則有\(n > x*y \quad and \quad n<x+y-1\),然後從後向前依次構造,保證過程中一直\(n,x,y\)一直滿足條件。
程式碼
ll T, n, x, y; int a[maxn], top; int main() { ios::sync_with_stdio(false); cin.tie(0); freopen("data.in", "r", stdin); //freopen("data.out", "w", stdout); cin >> T; while(T--) { cin >> n >> x >> y; if(n > x * y || n < x + y - 1) { cout << "NO\n"; continue; } cout << "YES\n"; int top = n; int now = n; while(n) { if(n >= x + y - 1) { for(int i = n - y; i < n; i++) a[i] = now--; x--; n -= y; } else { while(n < x + y - 1) y--; } } for(int i = 0; i < top; i++) { cout << a[i]; if(i != top - 1) cout << ' '; else cout << "\n"; } } return 0; }
1010 Jogging
題意
在無窮平面上給一個點,從這個點出發向任意\((x,y)\)走,要求\(gcd(x,y)>1\),詢問經過\(t\)次走動後能回到起點的期望。
思路
首先知道當能走到\((x,y) \quad, \quad x==y\)時,此時的概率為0,其他的情況則暴力走出所有能到達的點,答案是起點能到達的點為分子,所有點能到達的點總數為分母。
程式碼
ll x, y, up, down; map<pair<ll, ll>, int> mp; ll d[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; ll gcd(ll a, ll b) { return !b ? a : gcd(b, a % b); } int all(ll x, ll y) { int res = 1; for(int i = 0; i < 8; i++) { if(gcd(x + d[i][0], y + d[i][1]) > 1) res++; } return res; } void dfs(ll x, ll y) { if(x == y) down = -1; if(down == -1) return; mp[mkp(x, y)]++; down += all(x, y); for(int i = 0; i < 8; i++) { ll tx = x + d[i][0], ty = y + d[i][1]; if(!mp.count(mkp(tx, ty)) && gcd(tx, ty) > 1) { dfs(tx, ty); } } } void slove() { mp.clear(); scanf("%lld%lld", &x, &y); up = all(x, y), down = 0; dfs(x, y); if(down == -1) { printf("0/1\n"); return; } ll temp = gcd(up, down); up /= temp; down /= temp; printf("%lld/%lld\n", up, down); }