一共四道題 題目1 : 互補二元組
時間限制:10000ms
單點時限:1000ms
記憶體限制:256MB
描述
給定N個整數二元組(X1, Y1), (X2, Y2), … (XN, YN)。
請你計算其中有多少對二元組(Xi, Yi)和(Xj, Yj)滿足Xi + Xj = Yi + Yj且i < j。
輸入
第一行包含一個整數N。
以下N行每行兩個整數Xi和Yi。
對於70%的資料,1 ≤ N ≤ 1000
對於100%的資料,1 ≤ N ≤ 100000 -1000000 ≤ Xi, Yi ≤ 1000000
輸出
一個整數表示答案。
範例輸入
5
9 10
1 3
5 5
5 4
8 6
範例輸出
2
最初看到這道題的時候沒有認真審題,認為(1,2)(3,2)(3,2)這種情況只計數一次(應該記兩次),想辦法將配過對的數組刪除,結果耽誤了很長時間,後來先做的後面幾題,快結束時返回來再直接按字面意思做,過了70%(LTE)。比賽結束後翻到了某大神簡潔的代碼,膜拜。這道題將給定的條件Xi + Xj = Yi + Yj稍微變換一下可得 (Xi -Yi)+ (Xj - Yj) = 0, 所以將輸入的數對作差值儲存起來即可。考慮到X、Y的取值範圍,可用map直接尋找。嗯,以上的都能想到。大神的方法妙在儲存X-Y時,直接對Y-X做加操作,省去了重複遍曆和尋找,很巧妙。(注意X,Y的取值範圍,LL)
代碼:
#include<iostream>#include<algorithm>#include<vector>#include<string>#include<map>typedef long long ll;using namespace std;map<ll, ll> res;int main(){ int N; cin >> N; ll cnt = 0; int x, y; while(N--) { cin >> x >> y; cnt += res[x-y]; res[y-x]++; } cout << cnt << endl; return 0;}題目2 : 尋找切線
時間限制:10000ms
單點時限:1000ms
記憶體限制:256MB
描述
給定平面上N個點P1=(X1, Y1), P2=(X2, Y2), … PN=(XN, YN)。
請你從中找到兩個不同的點Pi和Pj滿足:其他所有點都在Pi和Pj連線的同一側(可以在連線上)。
如果有多組答案滿足條件,你可以輸出任意一組。
輸入
第一行包含一個整數N。
以下N行每行包含兩個整數Xi和Yi。
對於50%的資料,1 ≤ N ≤ 1000
對於100%的資料,1 ≤ N ≤ 100000 0 ≤ Xi, Yi ≤ 1000000
輸出
輸出由一個空格隔開的兩個整數i和j,注意1 ≤ i, j ≤ N且i ≠ j。
範例輸入
6
0 10
7 0
8 8
10 18
15 13
20 4
範例輸出
5 6
方法:一條直線由兩點確定:先找到 x/y 座標最大值(最小值也可以)作為第一個點,再計算其餘點與該點的斜率,取絕對值最大的點作為第二個點。
#include<iostream>#include<iostream>#include<algorithm>#include<vector>#include<string>#include<map>#include<cmath>#include<sstream>using namespace std;int main(){ int n; cin >> n; int x[n], y[n]; int m = 0, q = 0; for(int i=0; i<n; i++) { cin >> x[i] >> y[i]; if(x[i]>x[m]) m = i; } float k = 0; for(int i=0; i<n; i++) { if(i==m) continue; if(x[i]==x[m]) {q = i; break;} float k1 = abs(1.0*(y[i]-y[m])/(x[i]-x[m])); if(k1 > k) { k = k1, q = i;} } if(m < q) cout << m+1 << ' ' << q+1 << endl; else cout << q+1 << ' ' << m+1 << endl; return 0;}題目3 : LR問題
時間限制:10000ms
單點時限:1000ms
記憶體限制:256MB
描述
給定兩個字串S和T,每個字串都由’L’、’R’和’_’組成。例如:
R__LR_R_L
每一次操作,可以將S中的一個’R’與它右邊相鄰的’‘交換(前提是這個R右邊相鄰位置就是’‘);或者將S中的一個’L’與它左邊相鄰的’‘交換(前提是這個L左邊相鄰位置就是’‘)。
例如,先移動第一個L,再移動第二個R會得到:
R__LR_R_L -> R_L_R_R_L -> R_L__RR_L
請你計算最少經過幾次操作可以將S變成T。
輸入
第一行包含一個字串S。
第二行包含一個字串T。
對於30%的資料,1 ≤ |S| = |T| ≤ 20
對於100%的資料,1 ≤ |S| = |T| ≤ 100000
輸出
輸出一個整數代表最少操作次數。
如果不論如何S也不能變成T,輸出-1。
範例輸入
R__LR_R_L
R_L__RR_L
範例輸出
2
總是把簡單問題複雜化,竟然想用dp,做的題量還是太少了。參照某大神簡潔優美的代碼如下:
#include <iostream>#include <vector>using namespace std;int main(){ string s, t; cin>>s>>t; vector<int> ss, tt; for(int i=0;i<int(s.size());i++) if(s[i] != '_') ss.push_back(i); for(int i=0;i<int(t.size());i++) if(t[i] != '_') tt.push_back(i); if(ss.size() != tt.size()) return cout<<-1<<endl, 0; int ans = 0; for(int i=0;i<(ss.size());i++){ int sx = ss[i], tx = tt[i]; if(s[sx] != t[tx]) return cout<<-1<<endl, 0; if(s[sx] == 'L' && sx < tx) return cout<<-1<<endl, 0; if(s[sx] == 'R' && sx > tx) return cout<<-1<<endl, 0; ans += abs(sx - tx); } cout<<ans<<endl; return 0;}
題目4 : 推斷大小關係
時間限制:20000ms
單點時限:2000ms
記憶體限制:256MB
描述
有N個整數A1, A2, … AN,現在我們知道M條關於這N個整數的資訊。每條資訊是:
Ai < Aj 或者 Ai = Aj
小Hi希望你能從第一條資訊開始依次逐條處理這些資訊。一旦能推斷出A1和AN的大小關係就立即停止。
輸出在處理第幾條時第一次推斷出A1和AN的關係。如果處理完全部M條資訊還是不知道A1和AN的大小關係,輸出-1。
保證M條資訊是沒有矛盾的。
輸入
第一行包含兩個整數N和M。
以下M行每行包含一條資訊Ai < Aj 或者 Ai = Aj。
對於30%的資料,1 ≤ N ≤ 1000, 1 ≤ M ≤ 10000
對於100%的資料,1 ≤ N ≤ 100000, 1 ≤ N ≤ 1000000
輸出
一個整數表示答案。
範例輸入
5 8
A1 < A3
A3 < A2
A3 < A4
A5 < A2
A1 < A4
A1 < A2
A5 < A1
A5 < A3
範例輸出
7
參考了某大神的答案,嗯,,看懂了。知識點:二分尋找、dfs
#include <iostream>#include <cstdio>#include <vector>#include <cstring>using namespace std;const int maxn = 1e6 + 10;int x[maxn], op[maxn], y[maxn];int n, m;int fa[maxn];int Find(int x){ return fa[x] == x ? x : fa[x] = Find(fa[x]);}void Union(int x, int y){ x = Find(x), y = Find(y); fa[x] = y;}int vis[maxn];vector<int> G[maxn];void dfs(int x){ for(int i = 0; i < G[x].size(); i++) { int to = G[x][i]; if(vis[to]) continue; vis[to] = 1, dfs(to); }}bool check(int mid){ for(int i = 1; i <= n; i++) fa[i] = i, G[i].clear(); for(int i = 1; i <= mid; i++) if(op[i] == 0) Union(x[i], y[i]); for(int i = 1; i <= mid; i++) { if(op[i] == 1) G[Find(x[i])].push_back(Find(y[i])); if(op[i] == -1) G[Find(y[i])].push_back(Find(x[i])); } for(int i = 1; i <= n; i++) vis[i] = 0; vis[Find(1)] = 1; dfs(Find(1)); if(vis[Find(n)]) return true; for(int i = 1; i <= n; i++) vis[i] = 0; vis[Find(n)] = 1; dfs(Find(n)); if(vis[Find(1)]) return true; return false;}int id(char * s){ int l = strlen(s); int ret = 0; for(int i = 0; i < l; i++) ret = ret * 10 + (s[i] - '0'); return ret;}int main(void){ scanf("%d %d", &n, &m); for(int i = 1; i <= m; i++) { char a[11], b[11], c[11]; scanf("%s %s %s", a, b, c); cout << a << ' ' << b << ' '<< c << endl; x[i] = id(a + 1), y[i] = id(c +1); cout << x[i] << ' ' << y[i] << endl; if(b[0] == '>') op[i] = 1; if(b[0] == '<') op[i] = -1; } if(!check(m)) puts("-1"); else { int l = 1, r = m; while(l < r) { int mid = l + (r - l) / 2; if(check(mid)) r = mid; else l = mid +1; } printf("%d\n", r); } return 0;}