欧拉计划 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;
}