文章目录
- 01. HDU1062 Text Reverse
- 02. NOIP2004 火星人
- 03. POJ2259 Team Queue
- 04. UVA101 The Blocks Problem
- 05. UVA156 Ananagrams
- 06. UVA12096 The SetStack Computer
- 07. UVA1618 Weak Key
- 08. UVA10474 Where is the Marble
- 09. NOIP2004 合并果子
- 10. POJ1589 Unix Is
- 12. UVA10815 Andy's First Dictionary
- 13. POJ1338 Ugly Numbers
- 14. UVA1595 Symmetry
01. HDU1062 Text Reverse
-
思路:对于每一行读入后,在遇到空格或换行前都压入栈,有空格就全部倒序压出,再输出一个空格;有换行就倒序输出再输出一个换行即可。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 1e4 + 5; const db eps = 1e-10; using namespace std; int cas; string s; char c[N]; stack<char> st; int main(){ cin >> cas; getchar(); while(cas--){ gets(c); for(int i = 0; i <= strlen(c); i++){ if(c[i] == ' ' || i == strlen(c)){ //记住当i == strlen()时也是输出点!!! while(st.size()){ cout << st.top(); st.pop(); } if(c[i] == ' ') cout << " "; //PE警告:结尾不能加空格,只有c[i]为空格时才加 } else st.push(c[i]); } cout << endl; } }
02. NOIP2004 火星人
-
思路:运用计算全排列的next_permutation函数,向后数m次即可。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 1e4 + 5; const db eps = 1e-10; using namespace std; int n, m, a[N]; int main(){ cin >> n >> m; rep(i, 1, n) cin >> a[i]; //next_permutation全排列下一个, prev_permutation全排列上一个 while(m--) next_permutation(a + 1, a + 1 + n); rep(i, 1, n) cout << a[i] << " "; }
03. POJ2259 Team Queue
-
思路:要模拟一个team queue,可以对于每组team设计一个属于其自己的队列,储存本组被选的数;再用一个队列q[0]储存各组之间的顺序。这样插入一个数时,如果其组有数,直接压入到其组队列的末尾,否在在队列q[0]中先压入组号,新建其组队列压入即可。查询弹出时只需要在q[0]中组号排第一的组中找队头即可。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 1e3 + 5; const db eps = 1e-10; using namespace std; int t, team[1000005], cnt = 0, teamnum, x, n; char s[10]; int main(){ while(cin >> t, t){ teamnum = 0; rep(i, 1, t){ teamnum++; cin >> n; while(n--){ scanf("%d", &x); team[x] = teamnum; //记录 x 对应的队伍编号 } } printf("Scenario #%d\n", ++cnt); queue<int> q[N]; while(1){ scanf("%s", s); //string 字符串只能用 cin 读入(本题用时296ms)。char数组 用scanf读入不能加 & 符号(本题用时78ms)!!! if(s[0] == 'S') break; else if(s[0] == 'E'){ //排队的时候并不用将所有数排到一起,只需要记录每个 team 自己[入选的数]和 team 之间的[顺序]即可 scanf("%d", &x); int tmp = team[x]; if(!q[tmp].size()) q[0].push(tmp); //q[0] 是存队伍编号的队列 q[tmp].push(x); //q[tmp] 是存编号为 tmp 的数字的队列 } else{ int tmp = q[0].front(); printf("%d\n", q[tmp].front()); q[tmp].pop(); if(!q[tmp].size()) q[0].pop(); } } cout << endl; } }
04. UVA101 The Blocks Problem
-
思路:对于四种操作,发现只需要三种情况排列组合选择即可。于是写三种函数分别表示将所有上方物品放回原位、将x放到y栈顶、将x及上方物品按顺序放到y栈顶。对于每一个位置都设计一个不定长数组,对于每一个物品都用address记录其当前位置。对于三种操作分别调整即可。要注意最后输出时每行末尾不能有空格。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 1e6 + 5; const db eps = 1e-10; using namespace std; int n, a, b, address[30]; string command, s; vector<int> vec[30]; void Back(int x){ //将 x 上方物品放回原位 int stx = address[x], len; vector<int> &v = vec[stx]; len = v.size() - 1; while(v[len] != x){ int tmp = v[len]; v.pop_back(), vec[tmp].push_back(tmp); address[tmp] = tmp; len--; } } void onlygo(int x, int y){ //只将 x 放到 y 的栈顶上方 vec[address[x]].pop_back(), vec[address[y]].push_back(x); address[x] = address[y]; } void allgo(int x, int y){ //将 x 及上方物品放到 y 的栈顶上方 int stx = address[x], sty = address[y], lenx; vector<int> &v = vec[stx]; stack<int> stmp; lenx = v.size() - 1; while(v[lenx] != x){ stmp.push(v[lenx]), v.pop_back(); lenx--; } stmp.push(v[lenx]), v.pop_back(); while(stmp.size()){ int tmp = stmp.top(); stmp.pop(); vec[sty].push_back(tmp); address[tmp] = sty; } } int main(){ cin >> n; rep(i, 0, n - 1){ vec[i].push_back(i); address[i] = i; } while(1){ cin >> command; if(command == "quit") break; cin >> a >> s >> b; if(address[a] == address[b]) continue; //非法命令 if(command == "move"){ if(s == "onto"){ //a, b 上方均回原位,a到b上 Back(a), Back(b); onlygo(a, b); } else{ //a 上方回原位,a 到 b 的栈顶上 Back(a); onlygo(a, b); } } else{ if(s == "onto"){ //b 上方回原位,a 及上方到 b 上 Back(b); allgo(a, b); } else{ //a 及上方到 b 的栈顶上 allgo(a, b); } } } rep(i, 0, n - 1){ printf("%d:", i); int sz = vec[i].size(); if(sz) rep(j, 0, sz - 1) printf(" %d", vec[i][j]); printf("\n"); } }
05. UVA156 Ananagrams
-
思路:要查找所有不是反片语的词,那我们就要统计一下那些重复出现了。为了调整格式,使其统一,我们全部转为小写后将每个词内部按字符排序,再压入map自动排序所有词,若有重复就记录一下。最后统计所有只有一次的词找到其原词。将这些选出词排序后输出即可。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 1e2 + 5; const db eps = 1e-10; using namespace std; int cnt = 0; string s[N], t[N], ans[N]; // mp->first表示化为小写且内部排序后的字符串 // mp->second.first表示此字符串出现的次数 // mp->second.second表示此字符串对应 s 时的位置 map<string, pair<int, int> > mp; void Lower_Sort(string &x){ int ls = x.size(); rep(i, 0, ls - 1) if('A' <= x[i] && x[i] <= 'Z') x[i] += 32; sort(x.begin(), x.end()); } int main(){ while(cin >> s[++cnt], s[cnt] != "#") t[cnt] = s[cnt]; cnt--; rep(i, 1, cnt){ Lower_Sort(t[i]); if(mp.count(t[i])) mp[t[i]].first++; else mp.insert(make_pair(t[i], make_pair(1, i))); } map<string, pair<int, int> >::iterator iter; int num = 0; for(iter = mp.begin(); iter != mp.end(); iter++){ pair<int, int> tmp = iter->second; if(tmp.first == 1) ans[++num] = s[tmp.second]; //记录选择的字符串 } sort(ans + 1, ans + 1 + num); //按照原字符串字典序排序 rep(i, 1, num) cout << ans[i] << endl; }
06. UVA12096 The SetStack Computer
-
思路:对于任意一个不同集合,我们都尝试用一个数值id记录他,用map储存便于判断是否存在,用vector储存集合编号便于查询。题目中的UNION和INTERSECT操作都可以用set自带并集、交集函数实现。在最终总栈中,根据每次操作,不断改变栈内元素即可。则询问的栈顶元素大小,就可以根据vector中的编号查到此集合,再求大小即可。
//练习set, stack, map #include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define all(x) x.begin(), x.end() #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 1e6 + 5; const db eps = 1e-10; using namespace std; int cas, n; char s[10]; map<set<int>, int> mp; //记录是否有过此集合的map vector<set<int> > vec; //储存每个集合的编号 stack<int> st; //存集合的栈 int ID(set<int> x){ if(!mp.count(x)){ vec.push_back(x); mp[x] = vec.size() - 1; } return mp[x]; } int main(){ cin >> cas; while(cas--){ cin >> n; while(n--){ scanf("%s", s); if(s[0] == 'P') st.push(ID(set<int> ())); else if(s[0] == 'D') st.push(st.top()); else{ set<int> x1 = vec[st.top()]; st.pop(); set<int> x2 = vec[st.top()], tmp; st.pop(); if(s[0] == 'U') set_union(all(x1), all(x2), inserter(tmp, tmp.begin())); else if(s[0] == 'I') set_intersection(all(x1), all(x2), inserter(tmp, tmp.begin())); else{ tmp = x2; tmp.insert(ID(x1)); } st.push(ID(tmp)); } cout << vec[st.top()].size() << endl; //栈顶编号对应集合的大小 } cout << "***" << endl; } }
07. UVA1618 Weak Key
-
思路:这道题有点难,要充分利用不定长数组中的各种复杂度为O(logn)的查询。用两个数组h[i],l[i]分别记录每个数i后面大于、小于a[i]的位置j。比如对于第一个要求p<q<r<s,Nq>Ns>Np>Nr,遍历每个p,在h[p]中遍历每个q,在l[p]中找第一个大于q的数r,若r存在再在h[p]中找第一个大于r的s,若s存在再判断其是否能l[q]中,若存在便说明已找到。第二个要求同理,只是顺序相反。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = (a); i <= (b); i++) #define per(i, a, b) for(int i = (a); i >= (b); i--) #define ll long long #define db double #define all(x) x.begin(), x.end() #define VI vector<int> #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 5e3 + 5; const db eps = 1e-10; using namespace std; int cas, n, a[N]; VI h[N], l[N]; //h[i]存(j > i && a[j] > a[i]),l[i]存(j > i && a[j] < a[i]) bool find1(int p){ //找p < q < r < s && a[q] > a[s] > a[p] > a[r] if(h[p].empty()) return 0; rep(qnum, 0, h[p].size() - 1){ //从小到大先找 q, 再找 r, 最后找 s int q = h[p][qnum]; VI::iterator rpos = upper_bound(all(l[p]), q); //找 a[r] < a[p] 的第一个 r > q 的 r.用迭代器在 l[p] 中找 if(rpos == l[p].end()) continue; //没有 int r = *rpos; VI::iterator spos = upper_bound(all(h[p]), r); while(spos != h[p].end()){ int s = *spos; spos++; if(binary_search(all(l[q]), s)) return 1; } } return 0; } bool find2(int p){ //找p < q < r < s && a[q] < a[s] < a[p] < a[r] if(l[p].empty()) return 0; rep(qnum, 0, l[p].size() - 1){ int q = l[p][qnum]; VI::iterator rpos = upper_bound(all(h[p]), q); //找 a[r] > a[p] 的第一个 r > q 的 r if(rpos == h[p].end()) continue; //没有 int r = *rpos; VI::iterator spos = upper_bound(all(l[p]), r); while(spos != l[p].end()){ int s = *spos; spos++; if(binary_search(all(h[q]), s)) return 1; } } return 0; } bool solve(){ rep(i, 1, n) if((find1(i) || find2(i))) return 1; return 0; } int main(){ cin >> cas; while(cas--){ cin >> n; rep(i, 1, n){ scanf("%d", &a[i]); h[i].clear(), l[i].clear(); } rep(i, 1, n) rep(j, i + 1, n){ //预处理 if(a[j] > a[i]) h[i].push_back(j); else if(a[j] < a[i]) l[i].push_back(j); } puts(solve() ? "YES" : "NO"); } }
08. UVA10474 Where is the Marble
-
思路:对于每个数字,在排序后的不定长数组中找第一个大于等于要查询的数,若找到一致便输出,否则没有。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 1e6 + 5; const db eps = 1e-10; using namespace std; int n, q, a[N], cnt = 0; vector<int> vec; int main(){ while(cin >> n >> q, n || q){ vec.clear(); rep(i, 1, n){ int t; scanf("%d", &t); vec.push_back(t); } sort(vec.begin(), vec.end()); printf("CASE# %d:\n", ++cnt); rep(i, 1, q){ int t; scanf("%d", &t); int v = lower_bound(vec.begin(), vec.end(), t) - vec.begin(); if(vec[v] != t) printf("%d not found\n", t); else printf("%d found at %d\n", t, v + 1); } } }
09. NOIP2004 合并果子
-
思路:用优先队列每个找前两个最小的堆合并即可。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 1e4 + 5; const db eps = 1e-10; using namespace std; int n, a[N]; ll ans; priority_queue <int, vector<int>, greater<int> > q; int main(){ cin >> n; rep(i, 1, n){ cin >> a[i]; q.push(a[i]); } rep(i, 1, n - 1){ int first = q.top(); q.pop(); int second = q.top(); q.pop(); ans += first + second; q.push(first + second); } cout << ans << endl; }
10. POJ1589 Unix Is
-
思路:这道题重点是算出格子行列数和精确宽度,确定每列剩余宽度后填补空位即可。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 1e2 + 5; const db eps = 1e-10; using namespace std; int n, maxn, row, col; string s[N]; int main(){ while(cin >> n){ maxn = 0; rep(i, 1, n){ cin >> s[i]; maxn = max(maxn, (int)s[i].length()); } col = (60 - maxn) / (maxn + 2) + 1; //计算col row = n / col + (n % col == 0 ? 0 : 1); //计算row sort(s + 1, s + 1 + n); rep(i, 1, 60) cout << '-'; cout << endl; rep(i, 1, row){ rep(j, 0, col - 1){ int num = i + j * row, rest = maxn + (j == col - 1 ? 0 : 2) - (int)s[num].length(); //注意rest计算很容易PE if(num <= n){ cout << s[num]; rep(i, 1, rest) cout << " "; } } cout << endl; } } }
12. UVA10815 Andy’s First Dictionary
-
思路:对于读入的字符串,要把所有标点改成空格,再用流stringstream 重新读入一遍,将刷新空格后的字符串存入集合避免重复。最后按顺序输出即可。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 1e4 + 5; const db eps = 1e-10; using namespace std; string s; set<string> st; //set自带排序 int main(){ while(cin >> s){ rep(i, 0, s.size() - 1){ if(!isalpha(s[i])) s[i] = ' '; else s[i] = tolower(s[i]); } stringstream tmp(s); //流的输入输出: 将字符串作为完整读入流中,再输出 while(tmp >> s) st.insert(s); } for(auto i: st) cout << i << endl; }
13. POJ1338 Ugly Numbers
-
思路:用一个集合判断每次压入数字是否重复,用一个优先队列提取每次最小的数查询下一个是 * 2、* 3还是*5即可。最后枚举到第1500个即可。
//优先队列 #include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 2e3; const db eps = 1e-10; using namespace std; ll tmp, a[N]; set<int> flg; priority_queue<ll, vector<ll>, greater<ll> > q; int main(){ q.push(1), flg.insert(1); rep(i, 1, 1500){ tmp = a[i] = q.top(); //此时tmp一定是第i小的 q.pop(); if(!flg.count(tmp * 2)) //判断这个数之前是否存过 flg.insert(tmp * 2), q.push(tmp * 2); if(!flg.count(tmp * 3)) flg.insert(tmp * 3), q.push(tmp * 3); if(!flg.count(tmp * 5)) flg.insert(tmp * 5), q.push(tmp * 5); } printf("The 1500'th ugly number is %d.", a[1500]); //859963392 }
14. UVA1595 Symmetry
-
思路:由于只需要找竖线,那可以在读入后算出所有x轴的平均值。遍历每一个点,查看是否有关于此竖线对称的点存在,若没有直接break即可,小数需注意精度问题。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double #define PII pair<int, int> #define pi acos(-1.0) const int INF = 0x7fffffff; const int N = 1e3 + 5; const db eps = 1e-10; using namespace std; int cas, n, x, y; bool flg; db avg; PII a[N]; set<PII> st; bool cmp(PII a, PII b){ if(a.first == b.first) return a.second < b.second; return a.first < b.first; } int main(){ cin >> cas; while(cas--){ cin >> n; st.clear(); avg = 0; rep(i, 1, n){ int x1, y1; scanf("%d%d", &x1, &y1); avg += (db)x1; a[i] = make_pair(x1, y1), st.insert(a[i]); } avg /= (db)n, flg = 1; //若有对称轴,一定是平均值 rep(i, 1, n){ x = a[i].first, y = a[i].second; if(fabs(x - avg) <= eps) continue; if(!st.count(make_pair(2 * avg - x, y))){ //在集合中找是否有对应点 flg = 0; break; } } puts(flg ? "YES" : "NO"); } }