目錄
- A.空間
- B.卡片
- C.直線
- D.貨物擺放
- E.路徑
- G.砝碼稱重
A.空間

已知:
1MB = 1024KB
1KB = 1024B
一個陣列單元占用4B的位元組記憶體,所以答案為
256 * 1024 * 1024 / 4 = 67108864
B.卡片

用一個陣列存每種卡片還有多少張,再用一個回圈遍歷每個要湊的數,當卡片數不夠了就輸出答案
int a[10] = {2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021};
int main()
{
for (int i = 1; i; i ++ ){
int t = i;
while (t){
int s = t % 10;
if(a[s] >= 1) a[s] --;
else{
cout << i - 1 << endl;
return 0;
}
t /= 10;
}
}
}
答案:3181
C.直線

用四層回圈列舉所有點(x1, y1), (x2, y2)
然后用公式計算斜率和截距
k = (y2-y1) / (x2-x1)
b = (x2 * y1 - y2 * x1) / (x2 - x1)
再用map / set儲存一下每條直線的斜率和截距,需要注意的是要特判斜率為0的時候
typedef pair<double, double>PII;
map<PII, bool>mp;
int main()
{
for (int x1 = 0; x1 < 20; x1 ++ ){
for (int y1 = 0; y1 < 21; y1 ++ ){
for (int x2 = 0; x2 < 20; x2 ++ ){
for (int y2 = 0; y2 < 20; y2 ++ ){
if(x1 == x2) continue;
double k = (double)(y2 - y1) / (double)(x2 - x1);
double b = (double)(x2 * y1 - y2 * x1) / (x2 - x1);
mp[{k, b}] = true;
}
}
}
}
cout << mp.size() + 21;
}
答案:40257
D.貨物擺放

最簡單的思路肯定是 兩層for列舉,暴力求解,但是這樣做題目給的資料實在太大了,一定會超時,所以就要換思路,
首先令N = 2021401820211048
要三個數相乘等于N,那么這三個數一定是N的約數,所以我們可以列舉所有三個約數相乘的結果,如果等于N, 答案就+1
試除法求約數
void get_divisors()
{
for (int i = 1; i <= N / i; i ++ ){
if(N % i == 0)
{
if(i == N / i) a[t ++] = i;
else{
a[t ++] = i;
a[t ++] = N / i;
}
}
}
}
列舉三個約數相乘 (注意,一定要先把陣列排序)
sort(a, a + t);
int ans = 0;
for (int i = 0; i < t; i ++ ){
for (int j = 0; j < t; j ++ ){
if(a[i] * a[j] > N) break;
for (int k = 0; k < t; k ++ ){
if(a[i] * a[j] * a[k] == N) ans ++;
}
}
}
答案:2430
E.路徑

很明顯一道最短路的問題 (我當時用bfs跑了一個多小時暴出來的 )
:先建圖,再跑一邊dijkstra / spfa / floyd就可以
知識點:兩個數a, b的最大公倍數 = ( a * b / (a,b的最大公約數) )
而最大公約數可以用函式__gcd(a,b)來求
所以邊權為a * b / __gcd(a,b)
建圖:
void add(int a, int b)
{
int c;
c = a * b / __gcd(a, b);
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}
int main()
{
memset(h, -1, sizeof h);
for (int i = 1; i < 2021; i ++ ){
for (int j = i; j <= i + 21; j ++ ){
add(i, j);
}
}
}
再用最短路模板跑一遍
我用的是spfa 畢竟萬能
void spfa()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
st[1] = true;
queue<int>q;
q.push(1);
while (q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for (int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
if(dist[j] > dist[t] + w[i]){
dist[j] = dist[t] + w[i];
if(!st[j]){
st[j] = true;
q.push(j);
}
}
}
}
cout << dist[2021];
}
答案:10266837
F.時間顯示

首先 這題只要求顯示小時,分鐘,秒鐘, 那么我們就要先去掉每個整天的毫秒時間
long long n;
cin >> n;
int days = 1000 * 60 * 60 * 24;
n -= n / days * days;
這樣我們得到的時間就一定是從00:00開始不超過24小時的時間
然后就是很簡單的模擬了
int s = n / 1000; //多少秒
int min = s / 60; //多少分鐘
int hour = min / 60; //多少小時
s %= 60;
min %= 60;
hour %= 24;
if(hour < 10) cout << 0;
cout << hour << ':';
if(min < 10) cout << 0;
cout << min << ':';
if(s < 10) cout << 0;
cout << s;
G.砝碼稱重

一道DFS / DP 的題 但是DFS能拿一半的分,所以這里只講DP的解法
首先我們對于每個砝碼,有三種選法:放左邊,放右邊,不放,這樣看就是一個簡單的01背包問題

核心代碼
cin >> n;
int sum = 0;
for (int i = 1; i <= n; i ++ ){
cin >> a[i];
sum += a[i];
}
f[0][0] = 1;
for (int i = 1; i <= n; i ++ ){
for (int j = 0; j <= sum; j ++ ){
f[i][j] = f[i - 1][abs(j - a[i])] + f[i - 1][j] + f[i - 1][abs(j + a[i])];
}
}
如果能選到這個重量,那么f[i][j]的值就不為0,所以答案就為
int ans = 0;
for (int i = 1; i <= sum; i ++ ){
if(f[n][i]) ans ++;
}
cout << ans;
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/386804.html
標籤:其他
上一篇:Java常用的序列化框架
