2020百度之星程序設計大賽初賽二


A. Poker (Hdu 6775)

題目大意

給定n個幣,每次投至少m個,當投\(x\)個時,給回\(\lfloor x \times (1 - p \%) \rfloor\)。問你最多能投多少次。

解題思路

很顯然每次投\(m\)元是最優的,因為但凡投\(m+1\)元,給回的錢數不可能會增加二,要不不變要不減少。

每次投減少\(m - \lfloor m \times (1 - p \%) \rfloor\)個幣,先算出可以減少多少次,記為\(cnt\)次,剩余\(a\)個幣。

因為是給\(m\)個幣返回\(\lfloor m \times (1 - p \%) \rfloor\)個,我們要倒推回去\(k\)次,找到那一點,恰好滿足\(a + k \times (m - \lfloor m \times (1 - p \%) \rfloor) \geq m\)

\(k \geq \dfrac{m - a}{(m - \lfloor m \times (1 - p \%) \rfloor)}\)

所以 \(k = \lceil \dfrac{m - a}{(m - \lfloor m \times (1 - p \%) \rfloor)} \rceil\)

最終答案就是\(cnt - k + 1\)

(代碼是考慮小於號的情況)

神奇的代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        int n, m, p;
        cin >> n >> m >> p;
        if (n < m)
        {
            cout << 0 << endl;
            continue;
        }
        int qwq = m - m * (100 - p) / 100;
        int cnt = n / qwq;
        n %= qwq;
        cnt -= (m - n) / qwq;
        if ((m - n) % qwq == 0)
            ++cnt;
        cout << cnt << endl;
    }
    return 0;
}


B. Distance (Hdu 6776)

題目大意

告訴你\(n\)個人距離你的距離,問這\(n\)個人倆倆距離和最小值是是多少。

解題思路

很容易發現距離和最小就是這\(n\)個人位於同一條直線且位於你的同一邊,計算倆相鄰人之間的距離對答案的貢獻即可。

神奇的代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int kase;
    cin >> kase;
    for (int ii = 1; ii <= kase; ii++)
    {
        int n;
        cin >> n;
        vector<LL> qwq(n);
        for (int i = 0; i < n; ++i)
            cin >> qwq[i];
        sort(qwq.begin(), qwq.end());
        LL ans = 0;
        for (int i = 0; i < n - 1; ++i)
        {
            ans += (qwq[i + 1] - qwq[i]) * (LL)(i + 1) * (LL)(n - i - 1);
        }
        cout << ans << endl;
    }
    return 0;
}


C. Covid (Hdu 6777)

題目大意

\(n\)個人,告訴你每個人每刻的位置。如果有人和感染病毒的人在某一刻在同一位置,那么那人也被感染。初始只有1號人感染了,問最終感染人的編號。

解題思路

模擬時間流逝暴力搞就好了。

神奇的代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x)
{
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c))
        c = getchar();
    if (c == 45)
        s = 1, c = getchar();
    while (isdigit(c))
        x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s)
        x = -x;
}

template <typename T>
void write(T x, char c = ' ')
{
    int b[40], l = 0;
    if (x < 0)
        putchar(45), x = -x;
    while (x > 0)
        b[l++] = x % 10, x /= 10;
    if (!l)
        putchar(48);
    while (l)
        putchar(b[--l] | 48);
    putchar(c);
}

int main(void)
{
    int kase;
    read(kase);
    for (int ii = 1; ii <= kase; ii++)
    {
        int n;
        cin >> n;
        int tot = 0;
        vector<queue<pair<int, int>>> people(n);
        for (int len, t, p, i = 0; i < n; ++i)
        {
            cin >> len;
            for (int j = 1; j <= len; ++j)
            {
                cin >> t >> p;
                people[i].push(make_pair(t, p));
                tot = max(t, tot);
            }
        }
        vector<bool> sign(n, 0);
        sign[0] = true;
        int pos[12] = {0};
        for (int i = 1; i <= tot; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                if (sign[j] && (!people[j].empty()) && people[j].front().first == i)
                {
                    pos[people[j].front().second] = i;
                }
            }
            for (int j = 0; j < n; ++j)
            {
                if ((!people[j].empty()) && people[j].front().first == i)
                {
                    if (pos[people[j].front().second] == i)
                        sign[j] = true;
                    people[j].pop();
                }
            }
        }
        printf("1");
        for (int i = 2; i <= n; ++i)
            if (sign[i - 1])
                printf(" %d", i);
        puts("");
    }
    return 0;
}


D. Car (Hdu 6778)

題目大意

周一到周五限制車尾號0-9,一周一個車位號只能限一次。告訴你車牌號,問如何限號,才能使得每天未被限制的車的數量的最小值最大。輸出這個最值。

解題思路

枚舉每個車位號應該在哪一天限制,爆搜就好了。也就\(10^5\)種情況

神奇的代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x)
{
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c))
        c = getchar();
    if (c == 45)
        s = 1, c = getchar();
    while (isdigit(c))
        x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s)
        x = -x;
}

template <typename T>
void write(T x, char c = ' ')
{
    int b[40], l = 0;
    if (x < 0)
        putchar(45), x = -x;
    while (x > 0)
        b[l++] = x % 10, x /= 10;
    if (!l)
        putchar(48);
    while (l)
        putchar(b[--l] | 48);
    putchar(c);
}

void DFS(int tot, int cnt[], int sum[], int &ans, int n)
{
    if (tot == 10)
    {
        int qwq = 1e9;
        for (int i = 0; i < 5; ++i)
        {
            qwq = min(qwq, sum[i]);
        }
        ans = min(ans, n - qwq);
        return;
    }
    for (int i = 0; i < 5; ++i)
    {
        sum[i] += cnt[tot];
        DFS(tot + 1, cnt, sum, ans, n);
        sum[i] -= cnt[tot];
    }
}

int main(void)
{
    int kase;
    read(kase);
    for (int ii = 1; ii <= kase; ii++)
    {
        int n;
        read(n);
        int cnt[10] = {0};
        for (int x, i = 1; i <= n; ++i)
        {
            read(x);
            cnt[x % 10]++;
        }
        int ans = 1e9 + 7;
        int sum[5] = {0};
        DFS(0, cnt, sum, ans, n);
        write(ans, '\n');
    }
    return 0;
}


E. Drink (Hdu 6779)

題目大意

\(n\)個人,告訴你他們對於可樂、雪碧、芬達的喜好程度的排序。現在你有可樂、雪碧、芬達\(a,b,c(a+b+c=n)\)瓶,問如何分配,使得他們的快樂值最大。若一個人喝到第一喜歡的,有3快樂值;第二喜歡的,有2快樂值;第三喜歡的,有1快樂值。

解題思路

就一道費用流裸題。

由於喜好程度的排序只有六種情況,把人數壓成這六個點。

源點連三種飲料,容量為它們的瓶數,費用0。飲料連接六種情況,容量無窮,費用為相應的快樂值。六種情況連接匯點,容量為該情況的人數,費用為0。

由於是最大快樂值,把費用取相反數跑一遍最小費用最大流后取相反數即可。

神奇的代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x)
{
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c))
        c = getchar();
    if (c == 45)
        s = 1, c = getchar();
    while (isdigit(c))
        x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s)
        x = -x;
}

template <typename T>
void write(T x, char c = ' ')
{
    int b[40], l = 0;
    if (x < 0)
        putchar(45), x = -x;
    while (x > 0)
        b[l++] = x % 10, x /= 10;
    if (!l)
        putchar(48);
    while (l)
        putchar(b[--l] | 48);
    putchar(c);
}

#define MIN(a, b) (((a) < (b) ? (a) : (b)))
#define MAX(a, b) (((a) > (b) ? (a) : (b)))
#define fo(i, a, b) for (int i = (a); i <= (b); ++i)

#define M 30
#define N 12

const int INF = 23333333;
int head[N], nxt[M * 2], to[M * 2], flow[M * 2], cost[M * 2], pre[N], dis[N], team[N * 5], val[N], fr[M * 2];
int num, u, v, w, st, en;
bool vis[N];
LL ans;

void add(int u, int v, int f, int w)
{
    num++;
    nxt[num] = head[u];
    to[num] = v;
    fr[num] = u;
    flow[num] = f;
    cost[num] = w;
    head[u] = num;
    num++;
    nxt[num] = head[v];
    to[num] = u;
    fr[num] = v;
    flow[num] = 0;
    cost[num] = -w;
    head[v] = num;
}
inline bool SPFA()
{
    int l = 0, r = 1;
    team[1] = st;
    fo(i, st, en)
    {
        dis[i] = INF;
        pre[i] = 0;
        vis[i] = false;
    }
    dis[st] = 0;
    vis[st] = 1;
    while (l < r)
    {
        u = team[++l];
        for (int i = head[u]; i; i = nxt[i])
        {
            v = to[i];
            if (flow[i] && dis[v] > dis[u] + cost[i])
            {
                dis[v] = dis[u] + cost[i];
                pre[v] = i;
                if (!vis[v])
                {
                    team[++r] = v;
                    vis[v] = 1;
                }
            }
        }
        vis[u] = 0;
    }
    if (pre[en])
        return true;
    else
        return false;
}
inline void DFS()
{
    int qwq = INF;
    for (int i = pre[en]; i; i = pre[fr[i]])
        qwq = MIN(qwq, flow[i]);
    ans += (LL)qwq * (LL)dis[en];
    for (int i = pre[en]; i; i = pre[fr[i]])
    {
        flow[i] -= qwq;
        flow[i ^ 1] += qwq;
    }
}

int main(void)
{
    int kase;
    read(kase);
    for (int ii = 1; ii <= kase; ii++)
    {
        num = 1;
        ans = 0;
        int n, a, b, c;
        read(n);
        read(a);
        read(b);
        read(c);
        st = 0;
        en = 10;
        char qwq[4];
        int cnt[6] = {0};
        for (int i = 1; i <= n; ++i)
        {
            scanf("%s", qwq);
            if (strcmp(qwq, "012") == 0)
                cnt[0]++;
            if (strcmp(qwq, "021") == 0)
                cnt[1]++;
            if (strcmp(qwq, "102") == 0)
                cnt[2]++;
            if (strcmp(qwq, "120") == 0)
                cnt[3]++;
            if (strcmp(qwq, "201") == 0)
                cnt[4]++;
            if (strcmp(qwq, "210") == 0)
                cnt[5]++;
        }
        add(st, 1, a, 0);
        add(st, 2, b, 0);
        add(st, 3, c, 0);

        add(1, 4, INF, -3);
        add(1, 5, INF, -3);
        add(1, 6, INF, -2);
        add(1, 7, INF, -1);
        add(1, 8, INF, -2);
        add(1, 9, INF, -1);

        add(2, 4, INF, -2);
        add(2, 5, INF, -1);
        add(2, 6, INF, -3);
        add(2, 7, INF, -3);
        add(2, 8, INF, -1);
        add(2, 9, INF, -2);

        add(3, 4, INF, -1);
        add(3, 5, INF, -2);
        add(3, 6, INF, -1);
        add(3, 7, INF, -2);
        add(3, 8, INF, -3);
        add(3, 9, INF, -3);

        add(4, en, cnt[0], 0);
        add(5, en, cnt[1], 0);
        add(6, en, cnt[2], 0);
        add(7, en, cnt[3], 0);
        add(8, en, cnt[4], 0);
        add(9, en, cnt[5], 0);

        while (SPFA())
            DFS();
        write(-ans, '\n');
        for (int i = st; i <= en; ++i)
            head[i] = 0;
    }
    return 0;
}


F. Cloth (Hdu 6780)

題目大意

曬衣服,U字型,告訴你豎着的長度和橫着的長度的衣桿,衣服掛在上面,要求任意兩件的距離不小於\(x\),問最大曬多少件。

解題思路

qwq

神奇的代碼
qwq


G. Solo (Hdu 6781)

題目大意

\(n\)題,已知自己和對手完成每道題的時間,且對手從第1題開始寫。問如何安排順序,使得獲得的分數最大。

每一道題第一個選手AC即得一分。若同時完成則我得一分。

我完成了可以選擇任意時刻交,對手完成立刻交。

若有一題有人完成了,另一人會立刻放棄該題。

解題思路

一開始考慮的是設\(dp[i][j]\)表示前\(i\)題比對手超前\(j\)分鍾時獲得的最大分數,由於分鍾數達\(10^9\)爆空間,所以考慮數據范圍不那么大的狀態。

\(dp[i][j]\)表示前\(i\)題,得分為\(j\)時的最大超前對手時間。

然后考慮能否完成第\(i\)題以及是否寫第\(i\)題轉移即可。

\(dp[i+1][j+1] = \max(dp[i+1][j+1],dp[i][j]-(a[i+1]-b[i+1]))\ \ if\ \ \ dp[i][j]-(a[i+1]-b[i+1])\geq 0\)

\(dp[i+1][j] = \max(dp[i+1][j],dp[i][j] + b[i+1])\)

初始化\(dp[0][0]=0\),其余為\(-1\)

答案就是\(dp[n][i]\neq -1\)\(i\)的最大值。

神奇的代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x)
{
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c))
        c = getchar();
    if (c == 45)
        s = 1, c = getchar();
    while (isdigit(c))
        x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s)
        x = -x;
}

template <typename T>
void write(T x, char c = ' ')
{
    int b[40], l = 0;
    if (x < 0)
        putchar(45), x = -x;
    while (x > 0)
        b[l++] = x % 10, x /= 10;
    if (!l)
        putchar(48);
    while (l)
        putchar(b[--l] | 48);
    putchar(c);
}

const int N = 2e3 + 8;

LL dp[N][N];

LL a[N], b[N];

int main(void)
{
    int kase;
    read(kase);
    for (int ii = 1; ii <= kase; ii++)
    {
        int n;
        read(n);
        for (int i = 0; i <= n; ++i)
            for (int j = 0; j <= n; ++j)
                dp[i][j] = -1;
        for (int i = 1; i <= n; ++i)
        {
            read(a[i]);
        }
        for (int i = 1; i <= n; ++i)
        {
            read(b[i]);
        }
        dp[0][0] = 0;
        for (int i = 1; i <= n; ++i)
            for (int j = 0; j <= n; ++j)
            {
                if (dp[i - 1][j] != -1)
                {
                    if (dp[i - 1][j] + b[i] >= a[i])
                        dp[i][j + 1] = max(dp[i][j + 1], dp[i - 1][j] - (a[i] - b[i]));
                    dp[i][j] = max(dp[i][j], dp[i - 1][j] + b[i]);
                }
            }
        int ans = 0;
        for (int i = 0; i <= n; ++i)
            if (dp[n][i] != -1)
                ans = i;
        write(ans, '\n');
    }
    return 0;
}


H. Hanoi (Hdu 6782)

題目大意

qwq

解題思路

qwq

神奇的代碼
qwq



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM