比賽地址node
題目連接
⭐c++
解析:
直接使用dfs,模擬他的他的判斷過程便可。注意用一些trick,能夠將節點進行重編號(使得葉子節點按照滿二叉樹先序遍歷的順序進行編號),若是某個節點\(a\)是另外一個節點\(b\)的祖宗節點,則\(a\)必定是\(b\)的前綴,這樣就能夠去判斷是否有衝突算法
注意:數組
#include<bits/stdc++.h> using namespace std; int n, k; const int maxn = 5000; int dat[maxn]; int dfs(int cur, int x) { int cnt = 0; for (int i = 0; i < k; ++i) if (dat[i] >> x == cur) ++cnt; //trick if (cnt <= 1) return 1; return dfs(cur << 1, x - 1) + dfs(cur << 1 | 1, x - 1) + 1; } int main() { scanf("%d%d", &n, &k); for (int i = 0; i < k; ++i) scanf("%d", &dat[i]), dat[i] += n - 1; printf("%d", dfs(1, log(n) / log(2))); }
題目連接
⭐⭐函數
解析:優化
注意:
進一步優化發現能夠將前綴和數組與\(dp\)數組合並spa
#include<bits/stdc++.h> using namespace std; const int maxn = 55; int dat[maxn]; int main() { int T, n; scanf("%d", &T); while (T--) { scanf("%d", &n); bool ok = true; for (int i = 0; i < n; ++i) { scanf("%d", &dat[i]); if (i && dat[i] < dat[i - 1]) ok = false; } if (ok) printf("0\n"); else { if (dat[0] == n && dat[n - 1] == 1) printf("3\n"); else if (dat[0] == 1 || dat[n - 1] == n) printf("1\n"); else printf("2\n"); } } }
#include<bits/stdc++.h> using namespace std; const int maxn = 1e6 + 5; const long long mod = 1e9 + 7; long long inv[maxn], jc[maxn]; long long q_pow(long long a, long long b) { long long ans = 1; while (b) { if (b & 1) ans = ans * a % mod; a = a * a % mod; b >>= 1; } return ans; } typedef long long ll; ll C(int n, int m) { return jc[n] * inv[m] % mod * inv[n - m] % mod; } int main() { ll n, k; scanf("%lld%lld", &n, &k); inv[0] = inv[1] = jc[0] = jc[1] = 1; for (int i = 2; i <= n; ++i) jc[i] = jc[i - 1] * i % mod; inv[n] = q_pow(jc[n], mod - 2); for (int i = n - 1; i; --i) inv[i] = inv[i + 1] * (i + 1) % mod; int end = n / k; ll ans = 0; for (int i = 1; i <= end; ++i) { ans = (ans + C(n - i * (k - 1) - 1, i - 1)) % mod; } printf("%lld", ans); }
題目連接
⭐⭐code
解析:
好像就是以前cf的一道原題,因爲時刻要保證區間內\(0,1\)的數量相等,因此相隔\(k\)個距離的字符也必須相等,所以在保證字符串能夠知足上述條件的基礎上,再去觀察前\(k\)個字符是否能夠知足\(0,1\)的數量相等blog
#include<bits/stdc++.h> using namespace std; int n, k; const int maxn = 1000000 + 5; char str[maxn]; void no() { printf("No"); exit(0); } void yes() { printf("Yes"); exit(0); } int main() { scanf("%d%d", &n, &k); scanf("%s", str); if (k & 1) no(); int t[2] = { 0 }; int s = '0' + '1'; for (int i = 0; i < k; ++i) { if (str[i] == '0' || str[i] == '1') { ++t[str[i] == '1']; for (int j = i; j < n; j += k) if (str[j] == s - str[i]) no(); } else { char c = 0; for (int j = i; j < n; j += k) if (!c && str[j] != '?') c = str[j]; else if (c && str[j] != c) no(); if (c) ++t[c == '1']; } } if (t[1] > k / 2 || t[0] > k / 2) no(); yes(); }
題目連接
⭐⭐遊戲
解析:
在若是沒有要求第一個和最後一個珠子互相鄰近的狀況下,能夠很容易定義\(dp[i][j]\)表明到第\(i\)行,選擇\(j\)顏色的珠子時的最大價值
因此問題轉化成了如何解決相鄰的問題。能夠經過指定開始珠子的顏色爲紅色,或者爲藍色進行\(dp\),這樣就完美解決了問題
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6 + 10; const ll INF = -2e17; int T, w, n, m; ll dp[maxn][2], a[maxn], v[maxn][2], ans; int f(int x, int y) { return x * m + y; } int main() { scanf("%d", &T); while (T--) { scanf("%d%d", &n, &m); for (int i = 0; i < n; ++i) { v[i][0] = v[i][1] = INF; for (int j = 0; j < m; ++j) { scanf("%lld", &a[f(i, j)]); } } for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { scanf("%d", &w); v[i][w] = max(v[i][w], a[f(i, j)]); } } if (n == 1) { printf("%lld\n", max(v[0][0], v[0][1])); continue; } dp[0][0] = v[0][0]; dp[0][1] = INF; for (int j = 1; j < n; ++j) { dp[j][0] = max(dp[j - 1][0], dp[j - 1][1]) + v[j][0]; dp[j][1] = dp[j - 1][0] + v[j][1]; } ans = max(dp[n - 1][0], dp[n - 1][1]); dp[0][1] = v[0][1]; dp[0][0] = INF; for (int j = 1; j < n; ++j) { dp[j][0] = max(dp[j - 1][0], dp[j - 1][1]) + v[j][0]; dp[j][1] = dp[j - 1][0] + v[j][1]; } ans = max(ans, dp[n - 1][0]); printf("%lld\n", ans < 0 ? -1 : ans); } return 0; }
題目連接
⭐⭐
解析:
很是典型的最小費用最大流的模板題,構建超級源點鏈接有空餘車的城市,構建超級匯點鏈接缺車的城市,直接跑就好了
#include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; namespace MinCostMaxFlow { const static int MAXN = 1000;//node const static int MAXE = 10000;//edge struct Edge { int from, to, next, cap, flow; long long cost; Edge() {} Edge(int u, int v, int c, int f, long long _c, int nxt) :from(u), to(v), cap(c), flow(f), cost(_c), next(nxt) {} }edge[MAXE]; int head[MAXN], tol, N, start, end; int pre[MAXN]; long long dis[MAXN]; bool vis[MAXN]; //Function void init() { N = MAXN; tol = 0; memset(head, -1, sizeof(head)); } void link(int u, int v, int cap, int cost)//s->t,cap,cost { edge[tol] = Edge(u, v, cap, 0, cost, head[u]); head[u] = tol++; edge[tol] = Edge(v, u, 0, 0, -cost, head[v]); head[v] = tol++; } bool spfa() { queue<int>Q; for (int i = start; i <= end; i++) dis[i] = 0x3f3f3f3f3f3f3f3f; for (int i = start; i <= end; i++) vis[i] = false; for (int i = start; i <= end; i++) pre[i] = -1; dis[start] = 0; vis[start] = true; Q.push(start); while (!Q.empty()) { int u = Q.front(); Q.pop(); vis[u] = false; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if (!vis[v]) { vis[v] = true; Q.push(v); } } } } if (pre[end] == -1) return false; else return true; } int MCMF(long long& cost) { cost = 0; int maxflow = 0; while (spfa()) { int Min = INF; for (int i = pre[end]; i != -1; i = pre[edge[i ^ 1].to]) Min = min(Min, edge[i].cap - edge[i].flow); //MIN=min(Min,goal-maxflow); for (int i = pre[end]; i != -1; i = pre[edge[i ^ 1].to]) { edge[i].flow += Min; edge[i ^ 1].flow -= Min; cost += edge[i].cost * Min; } maxflow += Min; // if(maxflow==goal) break; } return maxflow; } }; const int maxn = 500 + 5; int dat[maxn]; int main() { int T, n, m, a, b, c; scanf("%d", &T); while (T--) { scanf("%d%d", &n, &m); MinCostMaxFlow::init(); MinCostMaxFlow::start = 0; MinCostMaxFlow::end = n + 1; int tot = 0; for (int i = 1; i <= n; ++i) scanf("%d", &dat[i]), tot += dat[i]; while (m--) { scanf("%d%d%d", &a, &b, &c); MinCostMaxFlow::link(a, b, INF, c); MinCostMaxFlow::link(b, a, INF, c); } if (tot % n) { printf("-1\n"); continue; } tot /= n; int top = 0; for (int i = 1; i <= n; ++i) { if (dat[i] > tot) MinCostMaxFlow::link(MinCostMaxFlow::start, i, dat[i] - tot, 0), top += dat[i] - tot; else if (dat[i] < tot) MinCostMaxFlow::link(i, MinCostMaxFlow::end, tot - dat[i], 0); } long long cost = 0; if (MinCostMaxFlow::MCMF(cost) != top) printf("-1\n"); else printf("%lld\n", cost); } }
題目連接
⭐⭐⭐⭐
解析:
能夠構造一個新的子游戲,子游戲能夠在樹上任意一點下棋,這樣根據SG定理,答案就成了鏈接在根節點(1號節點)上平行子游戲的異或和
對於子游戲的SG值,簡單畫了幾個樹形進行\(mex\)操做能夠發現,任一遊戲的SG值等於以他爲根節點的子游戲SG值得異或加1(具體證實待補...)
#include<bits/stdc++.h> using namespace std; int n; const int maxn = 1e5 + 5; vector<int> e[maxn]; int get_sg(int cur, int fa) { int t = 0; for (auto& i : e[cur]) if (fa != i) t ^= get_sg(i, cur); return t + 1; } int main() { int T, a, b; scanf("%d", &T); while (T--) { scanf("%d", &n); for (int i = 1; i <= n; ++i) e[i].clear(); for (int i = 1; i < n; ++i) { scanf("%d%d", &a, &b); e[a].push_back(b), e[b].push_back(a); } int ans = 0; for (auto& i : e[1]) ans ^= get_sg(i, 1); printf("%s\n", ans ? "NO" : "YES"); } }