hihoCoder 編程練習賽第45場__編程

來源:互聯網
上載者:User

一共四道題 題目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;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.