1. 程式人生 > 實用技巧 >L1-047 裝睡 (10分)

L1-047 裝睡 (10分)

A. Drink (Hdu 6743)

題目大意

給定\(n\)種飲料,每種無限瓶,每瓶飲料有水分\(x[i]\),包含\(y[i]\)卡路里。

現要求選一種飲料不斷喝,求攝入至少\(m\)水分下,得到的卡路里最小值。

解題思路

一開始沒看到只能喝一種飲料考慮DP,結果開場3分鐘就破百AC懷疑人生,他們都這麼快的嗎??

因為只能喝一種就列舉每一種飲料求最小值。

神奇的程式碼
#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;
        cin >> n >> m;
        int ans = 1e9 + 7;
        for (int x, y, i = 1; i <= n; ++i)
        {
            cin >> x >> y;
            ans = min(ans, (int)ceil(m * 1.0 / x) * y);
        }
        cout << ans << endl;
    }
    return 0;
}


B. GPA (Hdu 6744)

題目大意

給你四門總分,告訴你每一門中,成績對應的績點關係,問績點最高是多少。

解題思路

\(11^4\)種情況爆搜就好了。

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

double ans;

double ch(int x){
    if (x >= 95) return(4.3);
    if (x >= 90) return(4.0);
    if (x >= 85) return(3.7);
    if (x >= 80) return(3.3);
    if (x >= 75) return(3.0);
    if (x >= 70) return(2.7);
    if (x >= 67) return(2.3);
    if (x >= 65) return(2.0);
    if (x >= 62) return(1.7);
    if (x >= 60) return(1.0);
    return 0;
}

void solve(int x,int pos,double mark){
    if (pos==4){
        mark += ch(x);
        ans = max(ans, mark);
        return;
    }
    if (x >= 95) solve(x-95,pos+1,mark+4.3);
    if (x >= 90) solve(x-90,pos+1,mark+4.0);
    if (x >= 85) solve(x-85,pos+1,mark+3.7);
    if (x >= 80) solve(x-80,pos+1,mark+3.3);
    if (x >= 75) solve(x-75,pos+1,mark+3.0);
    if (x >= 70) solve(x-70,pos+1,mark+2.7);
    if (x >= 67) solve(x-67,pos+1,mark+2.3);
    if (x >= 65) solve(x-65,pos+1,mark+2.0);
    if (x >= 62) solve(x-62,pos+1,mark+1.7);
    if (x >= 60) solve(x-60,pos+1,mark+1.0);
    solve(x,pos+1,mark);
}

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); 
    cout.tie(0);
    int kase; cin>>kase;
    for (int ii=1,m; ii <= kase; ii++) {
        cin>>m;
        ans = 0;
        solve(m,1,0);
        cout<<fixed<<setprecision(1)<<ans<<endl;
    }
    return 0;
}


C. Dec (Hdu 5278)

題目大意

給定兩個正整數\(a,b\),每次操作可以讓\(a\)\(b\)減一,直到兩個都變為一,問整個過程中,出現\(a,b\)互質的情況數的最大值。

解題思路

抽象成平面上的點,左下角\((1,1)\),初始點\((a,b)\),一次可以向左或向下走一格,\(i,j\)互質點\((i,j)\)有一個貢獻,問從\((a,b)\)\((1,1)\)的所有路徑中,走到有貢獻點的最大值,Dp即可。預處理從(1,1)到所有點最大值。

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

int dp[1002][1002];

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)
{
    dp[1][1] = 1;
    for (int i = 1; i <= 1000; ++i)
        for (int j = 1; j <= 1000; ++j)
        {
            if ((i == 1) && (j == 1))
                continue;
            if (i == 1)
                dp[i][j] = dp[i][j - 1] + (__gcd(i, j) == 1);
            else if (j == 1)
                dp[i][j] = dp[i - 1][j] + (__gcd(i, j) == 1);
            else
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + (__gcd(i, j) == 1);
        }
    int kase;
    cin >> kase;
    for (int a, b, ii = 1; ii <= kase; ii++)
    {
        read(a);
        read(b);
        write(dp[a][b], '\n');
    }
    return 0;
}


D. Civilization (Hdu 6746)

題目大意

看原文吧,就是建城市得糧食得人口派人取工作繼續得糧食直到人口達到9問最短的時間。

解題思路

列舉建城市地點然後優先派人口到能取得糧食最多的地方工作,模擬模擬就好了。

神奇的程式碼
#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 dis(int i, int j, int x, int y)
{
    int qwq = abs(i - x) + abs(j - y);
    return (int)ceil(qwq * 1.0 / 2);
}

int a[505][505];

int n;

int dx[24] = {0, -1, 0, 1, -2, -1, 0, 1, 2, -3, -2, -1, 1, 2, 3, -2, -1, 0, 1, 2, -1, 0, 1, 0};

int dy[24] = {3, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -3};

int up[9] = {0, 1 * 1 * 8, 2 * 2 * 8, 3 * 3 * 8, 4 * 4 * 8, 5 * 5 * 8, 6 * 6 * 8, 7 * 7 * 8, 8 * 8 * 8};

int solve(int x, int y)
{
    vector<int> qwq;
    for (int i = 0; i < 24; ++i)
    {
        if ((x + dx[i] <= 0) || (x + dx[i] > n) || (y + dy[i] <= 0) || (y + dy[i] > n))
            continue;
        qwq.push_back(a[x + dx[i]][y + dy[i]]);
    }
    sort(qwq.begin(), qwq.end(), greater<int>());
    int cur = a[x][y];
    int people = 1;
    int ju = 0;
    size_t len = 0;
    int tot = 0;
    int gg = 0;
    while (people < 9)
    {
        gg = (int)ceil((up[people] - tot) * 1.0 / cur);
        ju += gg;
        tot += gg * cur;
        people++;
        if (len < qwq.size())
        {
            cur += qwq[len];
            ++len;
        }
    }
    return ju;
}

int main(void)
{
    int kase;
    read(kase);
    for (int x, y, ii = 1; ii <= kase; ii++)
    {
        read(n);
        read(x);
        read(y);
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                read(a[i][j]);
        int ans = 1e9 + 7;
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= n; ++j)
            {
                ans = min(ans, dis(i, j, x, y) + solve(i, j));
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}


E. Rotate (Hdu 6747)

題目大意

一個圓環由外到內分成\(n\)層,第\(i\)層被分為\(a[i]\)塊,\(a[i]\)是偶數,一半塗黑色一半塗白色,間隔塗。

現獨立旋轉每一層,每一層會等概率隨機終止一種局面,問黑色聯通塊個數的期望值。

\(a[i]\)不降。

解題思路

由於\(a[i]\)不降,塊的長度只會減小,所以第\(i+1\)層的黑塊至多與與第\(i\)層的中的一個黑塊會有接觸,這樣有接觸之間的黑塊連一條邊,它們就構成了一個森林。

對於森林,聯通塊數量 = 點數 - 邊數。

由期望的線性性質,E(聯通塊) = E(點數) - E(邊數)

\(E(\text{點數}) = \sum\limits_{i = 1}^{n} \dfrac{a[i]}{2}\)

對於邊數,第\(i+1\)層的一個黑塊與第\(i\)層的一個黑塊會有接觸的概率是

\[\frac{ \frac{2\pi}{a[i+1]} + \frac{2\pi}{a[i]}}{2\pi} = \frac{1}{a[i+1]} + \frac{1}{a[i]} \]

由期望定義知這也是期望邊數。

再乘以它們的數量即得

\[\left( \dfrac{1}{a[i+1]} + \dfrac{1}{a[i]} \right) \dfrac{a[i]}{2} \dfrac{a[i+1]}{2} = \dfrac{a[i] + a[i+1]}{4} \]

所以\(E(\text{邊數}) = \sum\limits_{i=1}^{n-1}\dfrac{a[i] + a[i+1]}{4}\)

\(E(\text{邊數})\)\(E(\text{點數})\)代入化簡得

\(E(\text{聯通塊}) = \dfrac{a[1] + a[n]}{4}\)

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

LL mo = 1e9 + 7;

int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int inv4 = 250000002;
    int kase;
    cin >> kase;
    for (int ii = 1; ii <= kase; ii++)
    {
        int n;
        cin >> n;
        int a;
        cin >> a;
        if (n == 1)
        {
            cout << a / 2 << endl;
            continue;
        }
        else
        {
            int b;
            for (int i = 2; i <= n; ++i)
                cin >> b;
            cout << (LL)(a + b) * inv4 % mo << endl;
        }
    }
    return 0;
}


F. Matrix (Hdu 6748)

題目大意

給定以原點作為中心的四個正方形,要求從被覆蓋的整點中選出\(k\)個,它們的權值最小。一個點\((x,y)\)的權值為它到原點的曼哈頓距離乘以被正方形覆蓋的次數。

解題思路

qwq

神奇的程式碼
qwq


G. Mosquito (Hdu 6749)

題目大意

給了一個網格圖,一些邊緣網格(窗戶)有一些蚊子,蚊子每一刻可以上下左右移動一格,不能移出網格,假設網格足夠聰明,問最少過多長時間,每個網格都有至少一隻蚊子。

解題思路

首先蚊子數少於網格數就直接輸出 -1。

考慮逆向,即初始時刻每個位置都有一隻蚊子,現在蚊子要飛回窗戶,問最少過多長時間,限制就是飛回某一窗戶的蚊子數不能多餘該窗戶原有的蚊子數。

先預處理出每個位置的蚊子飛到每一個窗戶所需要的時間。

很顯然時間越長,蚊子肯定能飛回窗戶,方案可行對時間具有單調性。

二分時間,得到每個蚊子能飛到哪些窗戶,再考慮如何分配哪些蚊子飛到哪些窗戶,可以看出是帶有反悔性的決策,跑一遍網路流即可判斷是否可行。

但蚊子數太多,如果我們把每隻蚊子與能飛到的窗戶連一條邊,點數和邊數會巨大,我們考慮如何壓點。

考慮到蚊子能飛到窗戶的情況數最多隻有\(2^6\)種,於是我們把能飛到窗戶的情況相同的蚊子都壓成一個點,這樣點數就只有\((2+6+2^6)\)

具體的連邊,就是源點與所有情況數連一條邊,容量為該情況對應的蚊子數;每種情況與對應的窗戶連一條邊,容量無限;每個窗戶與匯點連一條邊,容量是該窗戶初始有的蚊子數量。

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

#define MIN(a, b) (((a) < (b) ? (a) : (b)))
#define MAX(a, b) (((a) > (b) ? (a) : (b)))

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 M 100
#define N 640

const int INF = 233333333;
struct data
{
    int to, nxt, flow;
} line[N * 2];
int n, m, l, r, ans, team[M * 2], dis[M * 2], head[M * 2], num, u, v, st, en, qaq;

void add(int u, int v, int w)
{
    num++;
    line[num].nxt = head[u];
    line[num].to = v;
    line[num].flow = w;
    head[u] = num;
    num++;
    line[num].nxt = head[v];
    line[num].to = u;
    line[num].flow = 0;
    head[v] = num;
}
bool BFS()
{
    int u, v;
    l = r = 0;
    team[++r] = st;
    memset(dis, 0, sizeof(dis));
    dis[st] = 1;
    while (l < r)
    {
        u = team[++l];
        for (int i = head[u]; i; i = line[i].nxt)
        {
            v = line[i].to;
            if (dis[v] == 0 && line[i].flow)
            {
                dis[v] = dis[u] + 1;
                team[++r] = v;
            }
        }
    }
    if (dis[en])
        return true;
    else
        return false;
}
int DFS(int u, int f)
{
    if (u == en)
        return f;
    int tmp = 0;
    int qwq = 0;
    int v = 0;
    for (int i = head[u]; i; i = line[i].nxt)
    {
        v = line[i].to;
        if (dis[v] == dis[u] + 1 && line[i].flow)
        {
            qwq = DFS(v, MIN(f - tmp, line[i].flow));
            line[i].flow -= qwq;
            line[i ^ 1].flow += qwq;
            tmp += qwq;
            if (tmp == f)
                return tmp;
        }
    }
    return tmp;
}

int x[8], y[8], cnt[8];

int k;

int ddis[1001][1001][8];

int main(void)
{
    int t;
    read(t);
    while (t--)
    {
        read(n);
        read(m);
        read(k);
        long long qmq = 0;
        for (int i = 1; i <= k; ++i)
        {
            read(x[i]);
            read(y[i]);
            read(cnt[i]);
            qmq += (long long)cnt[i];
            for (int a = 1; a <= n; ++a)
                for (int b = 1; b <= m; ++b)
                {
                    ddis[a][b][i] = abs(a - x[i]) + abs(b - y[i]);
                }
        }
        if (qmq < (long long)n * m)
        {
            printf("-1\n");
            continue;
        }
        int tot = (1 << (k));
        st = 0;
        en = tot + k + 1;
        int l = 0, r = n + m;
        int cc[66] = {0};
        while (l < r)
        {
            int mid = (l + r) >> 1;
            num = 1;
            for (int i = st; i <= en; ++i)
                head[i] = 0;
            for (int i = 1; i <= n; ++i)
            {
                for (int j = 1; j <= m; ++j)
                {
                    int sign = 0;
                    for (int a = 1; a <= k; ++a)
                    {
                        if (ddis[i][j][a] <= mid)
                            sign |= (1 << (a - 1));
                    }
                    cc[sign]++;
                }
            }
            for (int i = 0; i < (1 << k); ++i)
            {
                for (int a = 1; a <= k; ++a)
                    if ((i >> (a - 1)) & 1)
                        add(i + 1, tot + a, INF);
                add(st, i + 1, cc[i]);
                cc[i] = 0;
            }
            for (int i = 1; i <= k; ++i)
                add(tot + i, en, cnt[i]);
            int dd = 0;
            while (BFS())
                dd += DFS(st, INF);
            if (dd < n * m)
                l = mid + 1;
            else
                r = mid;
        }
        write(r, '\n');
    }
    return 0;
}


H. Function (Hdu 6750)

題目大意

給定\(n\),計算\(\sum\limits_{i = 1}^{n} \sum\limits_{t|i} t [gcd(t,\dfrac{i}{t}) = 1]\)

解題思路

參考出處

化公式

\([gcd(t,\dfrac{i}{t}) = 1] = \epsilon(gcd(t,\dfrac{i}{t})) = \sum\limits_{d|gcd(t,\frac{i}{t})} \mu(d) 1(\frac{gcd(t,\frac{i}{t})}{d}) = \sum\limits_{d|gcd(t,\frac{i}{t})} \mu(d)\)出發。

\[\begin{aligned} \sum\limits_{i = 1}^{n} \sum\limits_{t|i} t [gcd(t,\dfrac{i}{t}) = 1] &= \sum\limits_{i = 1}^{n} \sum\limits_{t|i} t \sum\limits_{d|gcd(t,\frac{i}{t})} \mu(d) \\ &= \sum\limits_{i = 1}^{n} \sum\limits_{t|i} t \sum\limits_{d|t,d|\frac{i}{t}} \mu(d) \\ 調整順序,列舉\mu(d)考慮有多少個&= \sum\limits_{d = 1}^{n} \mu(d) \sum\limits_{t = 1}^{\lfloor \frac{n}{d} \rfloor} td \lfloor \frac{n}{d^2 t} \rfloor \\ (調整順序,將最右邊的d^2t看成關於\lfloor \frac{n}{d^2 t} \rfloor的自變數)&= \sum\limits_{t = 1}^{n} \lfloor \frac{n}{t} \rfloor \sum\limits_{d^2|t} \mu(d) \frac{t}{d} \\ 調整順序&= \sum\limits_{d = 1}^{\sqrt{n}} \mu(d) \sum\limits_{t = 1}^{\lfloor \frac{n}{d^2} \rfloor} \lfloor \frac{n}{d^2t} \rfloor \frac{td^2}{d} \\ &= \sum\limits_{d = 1}^{\sqrt{n}} \mu(d)d \sum\limits_{t = 1}^{\lfloor \frac{n}{d^2} \rfloor} t \lfloor \frac{n}{d^2t} \rfloor \\ G(x) = \sum\limits_{i = 1}^{x} t \lfloor \frac{i}{t} \rfloor \to &=\sum\limits_{d = 1}^{\sqrt{n}} \mu(d)d \cdot G \left( \lfloor \frac{n}{d^2} \rfloor \right) \end{aligned} \]

\(G(x)\)可用整數分塊求,求累加和也可用整數分塊求。

至於複雜度為什麼會有log不會qwq

神奇的程式碼
#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 LL mo = 1e9 + 7;

const LL N = 1e6 + 8;

bool visit[N];

LL prim[N];

int u[N];

LL sum_mu[N];

void pre_mu()
{
    sum_mu[0] = 0;
    memset(visit, false, sizeof(visit));
    int tot = 0;
    u[1] = 1;
    sum_mu[1] = 1;
    for (int i = 2; i <= N; i++)
    {
        if (!visit[i])
        {
            visit[i] = true;
            prim[++tot] = i;
            u[i] = -1;
        }
        for (int j = 1; j <= tot; j++)
        {
            if (prim[j] * i > N)
                break;
            visit[prim[j] * i] = true;
            if (i % prim[j])
                u[prim[j] * i] = -u[i];
            else
            {
                u[prim[j] * i] = 0;
                break;
            }
        }
        sum_mu[i] = (sum_mu[i - 1] + (LL)u[i] * i % mo + mo) % mo;
    }
}

LL inv2 = 500000004;

LL calc(LL l, LL r)
{
    LL nxt = 0;
    LL tmp = 0;
    while (l <= r)
    {
        nxt = r / (r / l);
        tmp = (tmp + (r / l) * ((l + nxt) % mo) % mo * ((nxt - l + 1) % mo) % mo * inv2 % mo) % mo;
        l = nxt + 1;
    }
    return tmp;
}

int main(void)
{
    pre_mu();
    int kase;
    read(kase);
    for (int ii = 1; ii <= kase; ii++)
    {
        LL n;
        LL ans = 0;
        read(n);
        LL up = sqrt(n);
        LL l = 1;
        LL nxt = 0;
        while (l <= up)
        {
            nxt = (LL)sqrt(n / (n / (l * l)));
            if (nxt > up)
                nxt = up;
            ans = (ans + calc(1, n / (l * l)) * ((sum_mu[nxt] - sum_mu[l - 1] + mo) % mo) % mo) % mo;
            l = nxt + 1;
        }
        write(ans, '\n');
    }
    return 0;
}