牛客小白月賽30題解(部分)
阿新 • • 發佈:2021-01-08
牛客小白月賽30題解(部分)
A.黑白邊
考點:並查集、最小生成樹
根據題可以看出,就是一道最小生成樹的裸模板題
程式碼:
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N = 2e5+10, INF = 0x3f3f3f3f; int n, m; int p[N]; struct Edge { int a, b, w; bool operator < (const Edge &t) const { return w < t.w; } }edges[N]; int find(int x) { if(p[x] != x) p[x] = find(p[x]); return p[x]; } int kruskal() { sort(edges, edges + m); for(int i = 1; i <= n; i++) p[i] = i; int res = 0, cnt = 0; for(int i = 0; i < m; i++) { int a = edges[i].a, b = edges[i].b, c = edges[i].w; a = find(a), b = find(b); if(a != b) { res += c; cnt++; p[a] = b; } } if(cnt < n-1) return INF; else return res; } int main() { cin >> n >> m; for(int i = 0; i < m; i++) scanf("%d%d%d", &edges[i].a, &edges[i].b, &edges[i].w); int t = kruskal(); if(t == INF) cout << -1 << endl; else cout << t << endl; return 0; }
B.最好的寶石
待補。。。。。。
C.滑板上樓梯
考點:貪心、數學
根據題意:要使次數最少,就要儘可能多走3步;3+1為一組,除一下,然後特判最後剩餘步數是否為3即可
程式碼:
#include <iostream>
using namespace std;
int main()
{
long long n;
cin >> n;
cout << n / 4 * 2 + ((n % 4) == 3 ? 1 : n % 4) << endl;
return 0;
}
D.GCD
考點:篩法求質數
分析題目可得:如果我們把1~n所有的質數和1全部放入子集,則任意兩個數的 gcd(x, y)
故要使題意成立,需滿足兩個條件:
1、1~n必須有合數
2、滿足1的條件下,k的最小值為 質數+2(包含1和1個合數)
解法:求出1~n所有的質數cnt,如果不等於n-1,則k = cnt+2;否則不存在輸出-1
程式碼:
#include <iostream> using namespace std; const int N = 1e5+10; int cnt, primes[N]; bool st[N]; void get_primes(int n) { for(int i = 2; i <= n; i++) { if(!st[i]) primes[cnt++] = i; for(int j = 0; primes[j] <= n / i; j++) { st[primes[j] * i] = true; if(i % primes[j] == 0) break; } } } int main() { int n; cin >> n; get_primes(n); if(cnt + 1 == n) cout << -1 << endl; else cout << cnt + 2 << endl; return 0; }
E.牛牛的加法
考點:高精度加法(大數加法)、模擬
高精度加法模板題
程式碼:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> A, B;
vector<int> add(vector<int> A, vector<int> B)
{
vector<int> C;
for(int i = 0; i < A.size() || i < B.size(); i++)
{
int t = 0;
if(i < A.size()) t += A[i];
if(i < B.size()) t += B[i];
C.push_back(t % 10);
}
return C;
}
int main()
{
string a, b;
cin >> a >> b;
for(int i = a.size() - 1; ~i; i--) A.push_back(a[i] - '0');
for(int i = b.size() - 1; ~i; i--) B.push_back(b[i] - '0');
vector<int> C = add(A, B);
while(C.size() > 1 && C.back() == 0) C.pop_back();
for(int i = C.size() - 1; ~i; i--) cout << C[i];
return 0;
}
F.石子合併
考點:貪心
貪心,每次選最大的和其相鄰的某一個,記錄總和,最後加上max*(n-2)即可
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
int n;
ll ans, m;
int main()
{
cin >> n;
for(int i = 0; i < n; i++)
{
ll a;
scanf("%lld", &a);
ans += a;
m = max(m, a);
}
cout << ans + m * (n - 2) << endl;
return 0;
}
G.滑板比賽
待補。。。。。。
H.第k小
待補。。。。。。
I.區間異或
待補。。。。。。
J.小遊戲
考點:動態規劃
程式碼:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 2e5+10;
int n, cnt[N];
long long f[N];
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
int a;
scanf("%d", &a);
cnt[a]++;
}
long long ans = 0;
for(int i = 0; i <= 2e5; i++)
{
f[i] = max(f[max(0,i - 1)], f[max(0, i - 2)] + i * cnt[i]);
ans = max(ans, f[i]);
}
cout << ans << endl;
return 0;
}