2020.02.22寒假集訓考試

序言:

​ 寒假就要結束了,馬上就要上網課了,剩下的時間就要複習和預習大一下的知識了,博客可能暫時停更了,謝謝大家的觀看。武漢加油!中國加油!

​ 今天是寒假集訓的最後一次考試了,題很不錯,思維題較多,涉及算法的並不多,感謝jwGG以及實驗室的學長學姐們親情出題,謝謝cy老師和jwGG的假期培訓。

​ 北大的dalao屠榜,😂,差距很大呀,我們仍需努力。
在這裏插入圖片描述

題解:

A:熊熊對對碰

map計數器的應用,因爲他要計算相反數和他本身的和,所以0的時候要考慮。

AC代碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
int n;
map<pair<int, int>, int> a;
pair<int, int> q;
int main()
{
    scanf("%d", &n);
    while (n--)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        if (a.count({-1 * x, -1 * y}) != 0) //如果它的相反數存在,就直接計算進去
        {
            a[{-1 * x, -1 * y}]++;
        }
        else //若他的相反是不存在,就計算它本身
            a[{x, y}]++;
    }
    int cnt = 0;
    for (map<pair<int, int>, int>::iterator i = a.begin(); i != a.end(); ++i)
    {
        if ((*i).second % 2 == 0)
            cnt += (*i).second;
    }
    printf("%d\n", cnt);
    return 0;
}

B:祕籍

前綴和+快慢指針尺取法的應用,暴力也可以。

AC代碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 300002;
int n, k;
int a[maxn];
bool flag = 0;
int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++)
    {
        int x;
        scanf("%d", &x);
        a[i] = a[i - 1] + x; //前綴和
    }
    int j = 1;
    for (int i = 0; i <= n && j <= n;) //快慢指針
    {
        if (a[j] - a[i] < k)
            j++;
        else if (a[j] - a[i] > k)
            i++;
        else
        {
            printf("%d %d", i + 1, j);
            flag = 1;
            break;
        }
    }
    if (flag == 0)
        puts("tiangeniupi");
    return 0;
}

C:jwGG的簽到題

數學公式的推導+審題,一開始沒審清題WA了兩發。因爲數據範圍的情況,要開unsigned long long。

在這裏插入圖片描述

AC代碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
int main()
{
    int t;
    ll a[20] = {0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, 9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999, 9999999999999999, 99999999999999999, 999999999999999999};
    scanf("%d", &t);
    while (t--)
    {
        unsigned long long cnt = 0;
        unsigned long long x, y;
        scanf("%llu%llu", &x, &y);
        for (int i = 1; i <= 18; i++)
        {
            if (a[i] <= y)
                ++cnt;
            if (a[i] > y)
                break;
        }
        cnt *= x;
        printf("%llu\n", cnt);
    }
    return 0;
}

D:jwMM的瘋狂A-B

最簡單的簽到題,set的應用。

AC代碼:

#include <bits/stdc++.h>
using namespace std;
int n, m;
int x;
set<int> a, b;
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &x);
        a.insert(x);
    }
    for (int i = 1; i <= m; i++)
    {
        scanf("%d", &x);
        b.insert(x);
    }
    int cnt = 0, flag = 0;
    for (set<int>::iterator it = a.begin(); it != a.end(); it++)
    {
        if (!b.count(*it))
        {
            printf("%d\n", *it);
            cnt++;
            flag = 1;
        }
    }
    if (!flag)
        puts("So crazy!!!");
    return 0;
}

E:煊哥的難題

太坑了。一開始我想了三種方法:第一種:叉積+直線重合,可以避免計算時的精度問題,但是比較難優化,只能暴力。第二種:斜率+截距的方法,可以進行map計數優化,但是計算時具有精度問題。第三種,還是斜率+截距,但是斜率用最簡的式表示,不用直接相除。

但最後,各種權衡之下,我還是選擇了第一種,然後就TLE,哎。

晚上看完jwGG講解後,標程就是選擇的第二種方法,那我就來說說第二組方法的題解吧。

  1. 選擇map進行計數 :在斜率存在時分別記錄斜率、y軸截距;在斜率不存在時,也就是垂直的時候,記錄垂直的條數和x軸截距。

  2. 在輸入座標的時候進行更新答案。

  3. 直線與直線的關係有三種:第一種:重合;第二種:相交;第三種:平行。雖然直線重合,但是這個也計算相交。我們只需要把當前錄入的所有直線 - 與當前直線平行的直線的數量。平行的直線=相同的斜率數量 - 相同的截距數量。
    ans+=i1(map[]map[]) ans+=i-1-(map[斜率]-map[截距])

AC代碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 100002;
int n, x[3], y[3];
double td, tk;
map<double, int> k;               //斜率->數量
map<pair<double, double>, int> d; //斜率,截距->數量,重合
map<int, int> d2;                 //垂直時候,截距->數量,重合
int cnt = 0;                      //垂直總個數
ll ans = 0;
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= 2; j++)
            scanf("%d%d", &x[j], &y[j]);
        if (x[1] == x[2]) //斜率不存在情況
        {
            td = x[1]; //x截距
            d2[td]++;
            cnt++;
            ans += (i - 1 - (cnt - d2[td]));
        }
        else
        {
            tk = (y[2] - y[1]) * 1.0 / (x[2] - x[1]); //k
            td = y[1] - tk * x[1];                    //y截距
            k[tk]++;
            d[{tk, td}]++;
            ans += (i - 1 - (k[tk] - d[{tk, td}]));
        }
    }
    printf("%lld\n", ans);
    return 0;
}

F: jwGG與yzMM的字符串

字符串的模擬題,先打解碼錶,最難想到的時解碼錶的打法,還有反推的過程。

  1. 我們選擇利用二維數組來進行解碼:密匙爲x,原文是y,加密後的文件爲z;這個式子代表用密匙x 來對加密後的文件z進行解密,還原成原文z

d[x][z]=y d[x][z]=y

  1. 我們如何得到d數組呢?這時候就要預先打標。
  2. 加密是正向加密,解密就要反向解密。

AC代碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 100002;
pair<int, int> p[maxn];
char a[55], b[130][130];
string s[1005];
void init()
{
    for (int i = 0; i <= 51; i++)
    {
        if (i <= 25)
            a[i] = 'A' + i;
        else
            a[i] = 'a' + i - 26;
    }
    for (int i = 0; i <= 51; i++)     //x
        for (int j = 0; j <= 51; j++) //y
        {
            int z = (i + j) % 52; //替換後的z,b中是存字符對應的ASCLLII
            b[a[i]][a[z]] = a[j];
        }
}
int main()
{
    ios::sync_with_stdio(false);
    int n, m;
    init();
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
        cin >> p[i].first >> p[i].second;
    for (int i = 1; i <= n; i++)
        cin >> s[i];
    for (int i = m; i >= 1; i--)
    {
        int y = p[i].second;
        int x = p[i].first;
        int len1 = s[x].size(), len2 = s[y].size();
        for (int i = 0; i < len2; i++)
            s[y][i] = (b[s[x][i % len1]][s[y][i]]);
    }
    for (int i = 1; i <= n; i++)
        cout << s[i] << endl;
    return 0;
}

G:jwGG與bwMM的字符串

暫時未作出,後續更新…


H:庫特放書

一道披着二分的暴力查找答案的題,直接放出題人的題解。

​ 爲什麼直接暴力不用二分在時間上是可行的吧,因爲我看所有通過代碼都寫的枚舉容量的上界是sum,但是如果上界真的是sum的話在時間上理論上是不可行的,這一點上並不是我數據出水了,是它的下界可以視爲max(ceil(sum / k),maxV),上界爲ceil(sum / k)+MAXV 所以枚舉次數爲二者之差遠達不到sum次,最多也不會超過1000次所以從下界while(1)向上尋找在時間上是可行的。

AC代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#include <iomanip>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
int t, n, m;
int v[1002];
bool vis[1002];
bool check(int tt)
{
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= m; i++)
    {
        int sum = 0;
        for (int j = 1; j <= n; j++)
        {
            if (sum + v[j] <= tt && vis[j] == 0)
            {
                sum += v[j];
                vis[j] = 1;
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        if (vis[i] == 0) //no
            return 0;
    }
    return 1;
}
int main()
{
    scanf("%d", &t);
    int k = 0;
    while (t--)
    {
        int sum = 0;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &v[i]);
            sum += v[i];
        }
        sort(v + 1, v + 1 + n, greater<int>());
        int l = sum / m, r = sum, ans;
        for (int i = l; i <= r; i++)
        {
            if (check(i))
            {
                ans = i;
                break;
            }
        }
        printf("Case #%d: %d\n", ++k, ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章