訓練賽地址ios
題目連接
⭐⭐⭐c++
題意:
有一個長爲\(L\)的停車道,座標從0開始,車輛停放時車頭朝向正方向,且距離車頭\(f\)範圍內和距離車尾\(b\)範圍內不能有其它車輛。
有兩種操做:數組
解析:函數
#include<bits/stdc++.h> using namespace std; /*===========================================*/ struct Tree { int l, r, lazy, ls, rs, mx; }; const int maxn = 1e6 + 205; struct Segment_Tree { Tree tree[maxn << 2]; void pushdown(int root) { if (~tree[root].lazy) { tree[root << 1].mx = tree[root << 1].ls = tree[root << 1].rs = (tree[root << 1].r - tree[root << 1].l) * tree[root].lazy; tree[root << 1 | 1].mx = tree[root << 1 | 1].ls = tree[root << 1 | 1].rs = (tree[root << 1 | 1].r - tree[root << 1 | 1].l) * tree[root].lazy; tree[root << 1].lazy = tree[root << 1 | 1].lazy = tree[root].lazy; tree[root].lazy = -1; } } void pushup(int root) { tree[root].ls = tree[root << 1].ls, tree[root].rs = tree[root << 1 | 1].rs; tree[root].mx = max(tree[root << 1].mx, tree[root << 1 | 1].mx); tree[root].mx = max(tree[root].mx, tree[root << 1].rs + tree[root << 1 | 1].ls); if (tree[root << 1].mx == tree[root << 1].r - tree[root << 1].l) tree[root].ls += tree[root << 1 | 1].ls; if (tree[root << 1 | 1].mx == tree[root << 1 | 1].r - tree[root << 1 | 1].l) tree[root].rs += tree[root << 1].rs; } void build(int k, int l, int r) { tree[k].l = l, tree[k].r = r; tree[k].ls = tree[k].rs = tree[k].mx = r - l; tree[k].lazy = -1; if (r - l != 1) build(k << 1, l, l + (r - l) / 2), build(k << 1 | 1, l + (r - l) / 2, r); } void update(int k, int ql, int qr, int val) { int& l = tree[k].l, & r = tree[k].r, & mx = tree[k].mx, & ls = tree[k].ls, & rs = tree[k].rs; if (ql <= l && r <= qr) { ls = rs = mx = (r - l) * val; tree[k].lazy = val; } else if (ql<r && qr>l) { pushdown(k); update(k << 1, ql, qr, val); update(k << 1 | 1, ql, qr, val); pushup(k); } } int query(int k, int val) { int& l = tree[k].l, & r = tree[k].r, & mx = tree[k].mx, & ls = tree[k].ls, & rs = tree[k].rs; if (tree[k << 1].mx >= val) { pushdown(k); return query(k << 1, val); } else if (tree[k << 1].rs + tree[k << 1 | 1].ls >= val) return tree[k << 1].r - tree[k << 1].rs; else if (tree[k << 1 | 1].mx >= val) { pushdown(k); return query(k << 1 | 1, val); } return -1; } }sol; pair<int, int> qu[105]; int main() { //freopen("abc.in", "r", stdin); int L, b, f; int n, opt, a; while (~scanf("%d%d%d", &L, &b, &f)) { L += b + f; sol.build(1, 0, L); scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d%d", &opt, &a); if (opt == 1) { int ans = sol.query(1, a + b + f); printf("%d\n", ans); if (ans == -1) continue; qu[i].first = ans + b; qu[i].second = qu[i].first + a; sol.update(1, qu[i].first, qu[i].second, 0); } else sol.update(1, qu[a].first, qu[a].second, 1); } } }
同時須要保存對應的操做數,操做結束後進行排序
3. 遇到2操做,\(O(n)\)查詢\(a\)所對應的車輛,進行刪除便可ui
#include<bits/stdc++.h> using namespace std; /*===========================================*/ struct Car { int id; int l, r; bool operator<(const Car& a)const { return l < a.l; } }; vector<Car> car; void solve() { int L, b, f, n; while (~scanf("%d%d%d", &L, &b, &f)) { car.clear(); car.push_back(Car{ -1, -b, -b }); car.push_back(Car{ -1,L + f,L + f }); int opt, a; scanf("%d", &n); for (int j = 1; j <= n; ++j) { scanf("%d%d", &opt, &a); if (opt == 1) { bool ok = false; for (int i = 1; i < car.size(); ++i) { if (car[i].l - car[i - 1].r >= a + b + f) { car.push_back(Car{ j,car[i - 1].r + b,car[i - 1].r + b + a }); printf("%d\n", car[car.size() - 1].l); ok = true; sort(car.begin(), car.end()); break; } } if (!ok) printf("-1\n"); } else for (int i = 1; i < car.size(); ++i) if (car[i].id == a) { car.erase(car.begin() + i); break; } } } } int main() { solve(); }
題目連接
⭐⭐編碼
題意:
給你三個整數,\(n,d,k\)。你的任務是從新構建出一棵樹或者判斷出不能構造出這樣的樹。\(n\)表明這棵樹一共有\(n\)個點,\(d\)表明的是這棵樹的直徑爲\(d\),\(k\)是每一個最大節點度數爲\(k\)。若是可以構造出這樣的樹,輸出‘YES’,和全部的邊。若是不能,那麼輸出‘NO’。spa
解析:.net
注意:code
#include<cstdio> #include<algorithm> #include<vector> using namespace std; int now; typedef pair<int, int> P; vector<P> v; int n, d, k; void dfs(int fa, int up, int lim) { if (now == n || !up || !lim) return; while (up--) { v.push_back(P(fa, ++now)); if (now == n) return; else dfs(now, k - 1, lim - 1); if (now == n) return; } } int main() { scanf("%d%d%d", &n, &d, &k); if (k == 1 && n > 2 || n <= d) { printf("NO"); return 0; } bool ok = false; now = d + 1; for (int i = 1; i <= d; ++i) v.push_back(P(i, i + 1)); for (int i = 2; i <= d; ++i) dfs(i, k - 2, min(i - 1, d + 1 - i)); if (now == n) { printf("YES\n"); for (auto& i : v) printf("%d %d\n", i.first, i.second); } else printf("NO"); }
題目連接
⭐⭐排序
題目:
給出\(n\)個數,從中選出長度爲\(k\)的子序列造成環,若是相鄰兩個元素之和不超過\(M\),求解\(M_{min}\)
解析:
注意:
#include<cstdio> #include<algorithm> using namespace std; const int maxn=2e5+5; int w[maxn]; int p[maxn]; int n,k; int ok(long long m) { int res=0; int cnt=0; for(int i=0;i<n;++i) if(w[i]<=m/2) p[cnt++]=i; if(cnt<=1) return cnt; for(int i=1;i<cnt;++i) for(int j=p[i-1]+1;j<p[i];++j) if(1ll*w[j]+max(w[p[i-1]],w[p[i]])<=m) { ++res; break; } for(int j=p[cnt-1]+1;j<n;++j) if(1ll*w[j]+max(w[p[cnt-1]],w[p[0]])<=m) return res+cnt+1; for(int j=0;j<p[0];++j) if(1ll*w[j]+max(w[p[cnt-1]],w[p[0]])<=m) return res+cnt+1; return res+cnt; } int main() { scanf("%d%d",&n,&k); for(int i=0;i<n;++i) scanf("%d",&w[i]); long long l=0,r=2e9+10,mid; while(l<r) { mid=l+(r-l)/2; if(ok(mid)>=k) r=mid; else l=mid+1; } printf("%lld",r); }
題目連接
⭐
題意:
給出¥1,¥5,¥10,¥50,四種鈔票,問\(n\)張鈔票能夠組成多少種不一樣的面額
解析:
初看題目很像一道dp,但發現\(n\)高達\(10^9\),果斷放棄
打表找規律不失爲一種好方法
注意:不開long long成神仙
總結:
經過打表發如今\(n>11\)時,答案是一個等差數列,公差爲49,這樣的話對\(n\le11\)部分進行特判,就解決了問題
打表代碼:
#include<bits/stdc++.h> using namespace std; /*===========================================*/ set<int> s; void dfs(int x, int cur, int num) { switch (x) { case 0: for (int i = 0; i <= cur; ++i) dfs(x + 1, cur - i, num + i); break; case 1: for (int i = 0; i <= cur; ++i) dfs(x + 1, cur - i, num + 5 * i); break; case 2: for (int i = 0; i <= cur; ++i) dfs(x + 1, cur - i, num + 10 * i); break; case 3: s.insert(num + cur * 50); } }
#include<bits/stdc++.h> using namespace std; /*===========================================*/ LL ans[] = { 0,4,10,20,35,56,83,116,155,198,244,292 }; int main() { LL n; scanf("%lld", &n); if (n <= 11) printf("%lld", ans[n]); else printf("%lld", ans[11] + 49 * (n - 11)); }
題目連接
⭐⭐⭐
題意:
給出\(n\)個獨立的單詞。在任意兩個相鄰的單詞之間有且僅有一個空格。須要注意的是,在第一個單詞以前沒有空格,在最後一個單詞以後也沒有空格。
如今能夠進行一次操做,將重複出現過的單詞以及他們之間的空格進行組合,造成一個單詞組,每一個單詞用一個字母表示,例如"\(ab\ cd\ ab\ cd\ ee\rightarrow A A\ ee\)",這個單詞組在原所給單詞序列中出現須要多於一次
問進行這樣的操做後,求單詞序列長度的最小值
解析:
能夠發現減小了\((\sum_{i=1}^nsz_i)+n-1\),而增長了單詞數量所對應的表明字符\(n\),因此總的來講減小了\((\sum_{i=1}^nsz_i)-1\),對結果統計最小值便可
#include<bits/stdc++.h> #define IOS std::ios::sync_with_stdio(0);cin.tie(0); using namespace std; /*===========================================*/ map<string, int> m; const int maxn = 305; int sz[maxn]; int a[maxn]; int nxt[maxn]; int cnt; int main() { IOS int n, res = 0; string s; cin >> n; for (int i = 0; i < n; ++i) { cin >> s; if (!m[s]) m[s] = ++cnt, sz[cnt] = s.size(); a[i] = m[s]; res += s.size(); } res += n - 1; int total = res; for (int lf = 0; lf < n; ++lf) { int len = 0; for (int ri = lf; ri < n; ++ri) { len += sz[a[ri]]; nxt[0] = -1; int cnt = 0; int i = 0, k = -1; while (i < ri - lf) { if (k == -1 || a[lf + i] == a[lf + k]) { if (a[lf + ++i] == a[lf + ++k]) // 當兩個字符相等時要跳過 nxt[i] = nxt[k]; else nxt[i] = k; } else k = nxt[k]; } nxt[ri - lf + 1] = 0; i = 0; // 主串的位置 int j = 0; // 模式串的位置 while (i < n) { if (j == -1 || a[i] == a[lf + j]) { ++i, ++j; if (j == ri - lf + 1) { ++cnt; j = nxt[j]; //操做 } } else j = nxt[j]; } if (cnt != 1) res = min(res, total - cnt * (len - 1)); } } cout << res; }