欧拉计划 81~90

81

定义状态转移方程:

\[dp[i][j] = \min(dp[i - 1][j], \, dp[i][j - 1]) + a[i][j] \]

// cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int a[N][N], dp[N][N];

int main() {
    freopen("matrix.txt", "r", stdin);
    int n = 80;
    for (int i = 1; i <= n; i ++ ) {
        string s;
        cin >> s;
        s += ',';
        int p = 0;
        for (int j = 1; j <= n; j ++ ) {
            int t = 0;
            while (s[p] != ',') t = t * 10 + s[p] - '0', p ++ ;
            p ++ ;
            a[i][j] = t;
        }
    }
    memset(dp, 0x3f, sizeof dp);
    dp[0][1] = 0;
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= n; j ++ ) {
            dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + a[i][j];
        }
    }
    cout << dp[n][n];
    return 0;
}

82

无他,多加一个状态而已。

// cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int a[N][N], dp[N][N];

int main() {
    freopen("matrix.txt", "r", stdin);
    int n = 80;
    for (int i = 1; i <= n; i ++ ) {
        string s;
        cin >> s;
        s += ',';
        int p = 0;
        for (int j = 1; j <= n; j ++ ) {
            int t = 0;
            while (s[p] != ',') t = t * 10 + s[p] - '0', p ++ ;
            p ++ ;
            a[i][j] = t;
        }
    }
    memset(dp, 0x3f, sizeof dp);
    for (int i = 1; i <= n; i ++ ) {
        dp[i][1] = a[i][1];
    }
    for (int j = 2; j <= n; j ++ ) {
        for (int i = 1; i <= n; i ++ ) {
            dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + a[i][j];
        }
        for (int i = n; i; i -- ) {
            dp[i][j] = min(dp[i][j], dp[i + 1][j] + a[i][j]);
        }
    }
    int ans = 1e9;
    for (int i = 1; i <= n; i ++ ) ans = min(ans, dp[i][n]);
    cout << ans;
    return 0;
}

83

利用 dijkstra 算法,我们可以在 \(O(n^4)\) 的复杂度下找到一条最短路径。

// cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 1010, INF = 0x7f7f7f7f;
int a[N][N], dp[N][N], st[N][N];

int main() {
    freopen("matrix.txt", "r", stdin);
    int n = 80;
    for (int i = 1; i <= n; i ++ ) {
        string s;
        cin >> s;
        s += ',';
        int p = 0;
        for (int j = 1; j <= n; j ++ ) {
            int t = 0;
            while (s[p] != ',') t = t * 10 + s[p] - '0', p ++ ;
            p ++ ;
            a[i][j] = t;
        }
    }
    memset(dp, 0x7f, sizeof dp);
    dp[1][1] = a[1][1];
    int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= n; j ++ ) {
            int px = 0, py = 0, minn = INF;
            for (int s = 1; s <= n; s ++ ) {
                for (int t = 1; t <= n; t ++ ) {
                    if (!st[s][t] && dp[s][t] < minn) {
                        minn = dp[s][t];
                        px = s, py = t;
                    }
                }
            }
            st[px][py] = 1;
            for (int k = 0; k < 4; k ++ ) {
                int x = px + dx[k], y = py + dy[k];
                if (!x || !y || x > n || y > n) continue;
                if (dp[x][y] > minn + a[x][y]) {
                    dp[x][y] = dp[px][py] + a[x][y];
                }
            }
            if (dp[n][n] != INF) break;
        }
    }
    cout << dp[n][n];
    return 0;
}

84

纯大模拟,随机化模拟即可。

# python
import random
result = [0 for i in range(40)]
cnt = 0
pos = 0
num = 0
limit = 1000000
while cnt<limit:
    r1 = random.randint(1, 4)
    r2 = random.randint(1, 4)
    pos += r1 + r2 
    if pos > 39:
        pos -= 40
    if r1 == r2:
        num += 1
    else:
        num = 0
    if pos == 2 or pos == 17 or pos == 33:
        r3 = random.randint(1,16)
        if r3 == 1:
            pos = 0
        if r3 == 2:
            pos = 10
    if pos ==7 or pos == 22 or pos == 36:
        r4 = random.randint(1,16)
        if r4 == 1:
            pos = 0
        if r4 == 2:
            pos = 10
        if r4 == 3:
            pos = 11
        if r4 == 4:
            pos = 24
        if r4 == 5:
            pos = 39
        if r4 == 6:
            pos = 5
        if r4 ==7 or r4 == 8:
            if pos == 7:
                pos = 12
            if pos == 22:
                pos = 25
            if pos == 36:
                pos = 5
        if r4 == 9:
            if pos == 7:
                pos =12
            if pos == 22:
                pos =28
            if pos == 36:
                pos =12
        if r4 == 10:
            pos -= 3
    if pos == 30 or num == 3:
        pos = 10
    if num == 3:
        num = 0
    result[pos] += 1
    cnt += 1

result = [1.0*re/limit for re in result]
for i in range(40):
    if result[i] > 0.03:
        print(i, result[i])

85

考虑 \(n \times m\) 长方形内矩形的数量:

\[\begin{aligned} C &= \sum_{i = 1}^n\sum_{j = 1}^m(n - i + 1)(m - j + 1) \\ &= \frac{n(n + 1)m(m + 1)}{4} \end{aligned} \]

考虑 \(\sqrt{2000000} < 1000\sqrt{2}\),直接在 \(1 \sim 1400\) 进行模拟即可。

# python
ans = 0
S = 0
target = 2e6
for i in range(1, 1400):
    for j in range(1, 1400):
        cnt = i * (i + 1) * j * (j + 1) // 4
        if abs(ans - target) > abs(cnt - target):
            ans = cnt
            S = i * j
print(S)

86

一条路径是长方体最短的,当且仅当边长 \(a \le b \le c\) 时,最短路径的长度为 \(\sqrt{(a + b)^2 + c^2}\),当确定一组 \(a + b\)\(c\) 是某组最短路径时,我们分两种情况讨论。

\(a + b < c\)

显然有 \(\left\lfloor\frac{a + b}{2}\right\rfloor\) 组,因为 \(a \le b\)

\(a + b > c\)

为满足方程 \(a \le b \le c\)

\[\begin{cases}a \le c \\ (a + b) - a \le c \\ a \le (a + b) - a\end{cases} \]

\((a + b) - c \le a \le \frac{a + b}{2}\),因此共有 \(c - \frac{a +b}{2} + 1\) 组。

综上遍历即可。

# python
from gmpy2 import *
c = 1
cnt = 0
while cnt < 1e6:
    c += 1
    for sum in range(2, 2 * c):
        path = gmpy2.iroot(sum * sum + c * c, 2)
        if path[1] == True:
            if sum > c:
                cnt += c - (sum + 1) // 2 + 1
            else:
                cnt += sum // 2
print(c)

87

筛素数后暴力判即可。

// cpp
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10, M = 5e7;
int primes[N], cnt;
bool st[N], is[M];

int main() {
    for (int i = 2; i < N; i ++ ) {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; i * primes[j] < N; j ++ ) {
            st[i * primes[j]] = 1;
            if (i % primes[j] == 0) break;
        }
    }
    for (int i = 0; ; i ++ ) {
        int a = primes[i] * primes[i];
        if (a >= M) break;
        for (int j = 0; ; j ++ ) {
            int b = primes[j] * primes[j] * primes[j];
            if (a + b >= M) break;
            for (int k = 0; ; k ++ ) {
                int c = primes[k] * primes[k] * primes[k] * primes[k];
                if (a + b + c >= M) break;
                is[a + b + c] = 1;
            }
        }
    }
    int ans = 0;
    for (int i = 2; i < 5e7; i ++ ) 
        if (is[i]) ans ++ ;
    cout << ans;
    return 0;
}

88

容易发现,\(2k\) 是所有情况的上界,因为 \(2k = k + 2 + (k - 2) \times 1 = k * 2\),据此,枚举所有的数,找到它所能满足的最小 \(k\),这很简单,枚举它的因数和即可,注意去重。

// cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int is[N];

int maxk = 12000;

// number, factors sum, number of numbers, factor
void dfs(int num, int sum, int cnt, int p) {
    int k = num - sum + cnt;
    if (k > maxk) return;
    if (num < is[k]) is[k] = num;
    for (int i = p; i * num <= maxk * 2; i ++ ) {
        dfs(num * i, sum + i, cnt + 1, i);
    }
}

int main() {
    memset(is, 0x3f, sizeof is);
    for (int i = 2; i <= maxk; i ++ ) dfs(i, i, 1, i);
    sort(is + 2, is + maxk + 1);
    int ed = unique(is + 2, is + maxk + 1) - is;
    int ans = 0;
    for (int i = 2; i < ed; i ++ ) ans += is[i];
    cout << ans;
    return 0;
}

89

恶心模拟题,见代码。

// cpp
#include<bits/stdc++.h>
using namespace std;
map<char, int> mp;

int main() {
    mp['M'] = 1000, mp['D'] = 500, mp['C'] = 100, mp['L'] = 50, mp['X'] = 10, mp['V'] = 5, mp['I'] = 1;
    mp['m'] = 900, mp['d'] = 400, mp['c'] = 90, mp['l'] = 40, mp['x'] = 9, mp['v'] = 4;
    freopen("roman.txt", "r", stdin);
    string s;
    int ans = 0;
    while (cin >> s) {
        ans += s.length();
        int num = 0, cnt = 0;
        for (int i = 0; i < s.length(); i ++ ) {
            if (i < s.length() - 1 && s[i] == 'C' && s[i + 1] == 'M') num += 900, i ++ ;
            else if (i < s.length() - 1 && s[i] == 'C' && s[i + 1] == 'D') num += 400, i ++ ;
            else if (i < s.length() - 1 && s[i] == 'X' && s[i + 1] == 'C') num += 90, i ++ ;
            else if (i < s.length() - 1 && s[i] == 'X' && s[i + 1] == 'L') num += 40, i ++ ;
            else if (i < s.length() - 1 && s[i] == 'I' && s[i + 1] == 'X') num += 9, i ++ ;
            else if (i < s.length() - 1 && s[i] == 'I' && s[i + 1] == 'V') num += 4, i ++ ;
            else num += mp[s[i]];
        }
        cnt += num / 1000, num %= 1000;
        cnt += num / 900 * 2, num %= 900;
        cnt += num / 500, num %= 500;
        cnt += num / 400 * 2, num %= 400;
        cnt += num / 100, num %= 100;
        cnt += num / 90 * 2, num %= 90;
        cnt += num / 50, num %= 50;
        cnt += num / 40 * 2, num %= 40;
        cnt += num / 10, num %= 10;
        cnt += num / 9 * 2, num %= 9;
        cnt += num / 5, num %= 5;
        cnt += num / 4 * 2, num %= 4;
        cnt += num;
        ans -= cnt;
    }
    cout << ans;
    return 0;
}

90

根据题意,我们不难发现需要分别在两个立方体上的数字应有这些对子:

  • \(0 \leftrightarrow 1\)
  • \(0 \leftrightarrow 4\)
  • \(0 \leftrightarrow 6/9\)
  • \(1 \leftrightarrow 6/9\)
  • \(1 \leftrightarrow 8\)
  • \(2 \leftrightarrow 5\)
  • \(3 \leftrightarrow 6/9\)
  • \(4 \leftrightarrow 6/9\)

使用状态压缩进行搜索,骰子的状态数为 \(210\),因此状态量极少,可以完成。

// cpp
#include<bits/stdc++.h>
using namespace std;
pair<int, int> p[8] = {{0, 1}, {0, 4}, {0, 6}, {1, 6}, {1, 8}, {2, 5}, {3, 6}, {4, 6}};
int ans = 0;

void check(int dice1, int dice2) {
    int pd = 0;
    if (dice1 >> 9) dice1 |= 1 << 6;
    if (dice2 >> 9) dice2 |= 1 << 6;
    for (int i = 0; i < 8; i ++ ) {
        if (dice1 >> p[i].first & dice2 >> p[i].second & 1) pd |= 1 << i;
        if (dice2 >> p[i].first & dice1 >> p[i].second & 1) pd |= 1 << i;
    }
    if (pd + 1 == 1 << 8) ans ++ ;
}

void dfs(int dice1, int dice2, int cnt, int p1, int p2) {
    if (cnt == 6) return check(dice1, dice2), void();
    if (!p1 || !p2) return;
    for (int i = p1 - 1; i >= 0; i -- ) {
        for (int j = p2 - 1; j >= 0; j -- ) {
            int n1 = dice1 | (1 << i), n2 = dice2 | (1 << j);
            if (n1 > n2) continue;
            dfs(n1, n2, cnt + 1, i, j);
        }
    }
}

int main() {
    dfs(0, 0, 0, 10, 10);
    cout << ans;
    return 0;
}
posted @ 2025-03-18 00:52  YipChip  阅读(22)  评论(0)    收藏  举报